Purpose

This work aims to develop sets of tools and procedures that will help trader to efficiently guess Financial Asset Market Type. Whether it’s a Bullish or Bearish Market, Ranging, Volatile - Author believes that having this ability to detect market type and use it in trading would be of a great advantage!

In order to test the approach secondary method will be developed. That is to identify best ‘entry’ pattern.

Whenever this attempt fails, there would still be learning left! Reader would be still capable to know how to Use Deep Learning for Regression/Classification problems

Task outlay

Basic idea of achieveing this will be:

Load packages

Note: use R script attached to this repository called: 6_h2o_Install.R to install h2o on your computer

library(tidyverse)
library(lubridate)
library(plotly)
library(h2o)

Data read

Here we can get into the financial data. Financial data can be read and refreshed using MQL side. How to do this is explained in the Udemy course. For the reproducibility purposes and for those who are not planning to trade sample data is available in the repository:

# use this option to use sample data:
macd <- read_csv("AI_Macd15.csv", col_names = F)
Parsed with column specification:
cols(
  .default = col_double(),
  X1 = col_character()
)
See spec(...) for full column specifications.

Catching specific market periods

Here we would need to manually change Y variable in the plot until finding siutable market condition…

  1. Bull normal
  2. Bull volatile
  3. Bear normal
  4. Bear volatile
  5. Sideways quiet
  6. Sideways volatile

This is ‘manual’ part of things with a chance of bias. Fellow reader can certainly create custom functions to select periods automatically. Author of this text is too lazy to do that and trust more to the personal brain to do so

Example of data selection for one Market Type: Bull normal

Code below will create time-series plot of one currency pair

We will extract only corresponding piece in this case starting from November’2017…

# extract approximate date and choose only relevant columns
bull_norm <- prices %>% filter(X1 > "2017-11-05", X1 < "2017-11-25") %>% select(X1, X3)

… and visualize it to confirm

next, we can extract corresponding piece of macd dataframe:

macd_bull_norm <- macd %>% select(X1, X3) %>% inner_join(bull_norm, by = c("X1" = "X1"))

and visualize both things together

let’s now use this function:

macd_m_bull_norm <- macd_bull_norm %>% select(X3.x) %>% to_m(100)

…to convert this dataset to the matrix with 100 columns

Visualize new matrix in 3D

and now we can see the obtained surface as 3D plot. In this case we have 14 rows. Each of these rows will contain 100 datapoints Tip: try to rotate obtained object and notice that majority of points are located in the positive area. Of course there were also ‘corrections’ hence some rows are in the negative side…

Brief explanation is probably required. Why do we use 100 datapoints (or less) in one row? The meaning of those will be to give use the pattern or fingerprint of that one specific market period. The goal of our model later will be exactly this. To digest the last observations through the model and output the value or category hence recognizing what is the specific market type…

Let’s however make some more considerations. Why don’t we say to guess our market type decision on the last 8 hours hence 8*60/15 which will result 32 M15 bars:

We have seen that the majority of our observations are in the ‘positive’ area, however some of the observations do not! For that reason it would be much better perhaps remove those observations that are not up to our pattern! Why not to try Deep Learning Autoencoders?

what about unsupervised learning?

The key idea now will be to train Deep Learning autoencoder model on that selected dataset. We will ‘send’ this dataset to our JVM:

# load data into h2o environment
macd_bv  <- as.h2o(x = macd_m_bull_norm, destination_frame = "macd_bull_norm")

  |                                                                                                                                                             
  |                                                                                                                                                       |   0%
  |                                                                                                                                                             
  |=======================================================================================================================================================| 100%

Then we will fit the model:

# fit the model
deepnet_model <- h2o.deeplearning(
 x = names(macd_bv), 
 training_frame = macd_bv, 
 activation = "Tanh", 
 autoencoder = TRUE, 
 hidden = c(20,8,20), 
 sparse = TRUE,
 l1 = 1e-4, 
 epochs = 100)

  |                                                                                                                                                             
  |                                                                                                                                                       |   0%
  |                                                                                                                                                             
  |==========================================================================================================                                             |  70%
  |                                                                                                                                                             
  |=======================================================================================================================================================| 100%

Any time need to make a pause?

h2o.shutdown(prompt = F)
[1] TRUE

We can now use this model to extract anomalous records. Records that would not be corresponding to our ‘bullish’ pattern will have higher mse value, for example:

We now can find indexes of observations where mse error is higher than 0.005

Finally let’s try to see if we could now filter the outliers:

8 observations were filtered…

Well it seems that we could filter our observations but not completely. Besides, it is probably questionable if we should do that in the first place…

Next we can create a code that will help to select data for every market type and combine that to one specific dataframe

Now we have our labelled dataset

Regression model

Next we can fit the model just by specifying what are the ‘Label’ column. In this case our label is a numeric.

Model we will fit in this case will have configuration:

Inputs hidden layer1 hidden layer2 Output
32 100 100 1
#### Fitting Deep Learning Net =================================================
## Fit model now:
# start h2o virtual machine
h2o.init()
 Connection successful!

R is connected to the H2O cluster: 
    H2O cluster uptime:         1 hours 5 minutes 
    H2O cluster timezone:       Europe/Berlin 
    H2O data parsing timezone:  UTC 
    H2O cluster version:        3.18.0.4 
    H2O cluster version age:    20 days  
    H2O cluster name:           H2O_started_from_R_fxtrams_nux062 
    H2O cluster total nodes:    1 
    H2O cluster total memory:   1.60 GB 
    H2O cluster total cores:    4 
    H2O cluster allowed cores:  4 
    H2O cluster healthy:        TRUE 
    H2O Connection ip:          localhost 
    H2O Connection port:        54321 
    H2O Connection proxy:       NA 
    H2O Internal Security:      FALSE 
    H2O API Extensions:         Algos, AutoML, Core V3, Core V4 
    R Version:                  R version 3.4.3 (2017-11-30) 

It takes a while until it is trained:

ModelA
summary(ModelA)
h2o.performance(ModelA)

Notice that model is making mistakes sometimes even returning negative values!

In fact we should try different models until results are better while choosing less possible complexity model, for example:

# fit models from simplest to more complex
ModelB <- h2o.deeplearning(
  x = names(macd_ML[,1:32]), 
  y = "M_T",
  training_frame = macd_ML,
  activation = "Tanh",
  overwrite_with_best_model = TRUE, 
  autoencoder = FALSE, 
  hidden = c(30,20,30), 
  loss = "Automatic",
  sparse = TRUE,
  l1 = 1e-4,
  distribution = "AUTO",
  stopping_metric = "MSE",
  #balance_classes = T,
  epochs = 600)

  |                                                                                                                                          
  |                                                                                                                                    |   0%
  |                                                                                                                                          
  |==                                                                                                                                  |   2%
  |                                                                                                                                          
  |============================================                                                                                        |  33%
  |                                                                                                                                          
  |====================================================================================                                                |  63%
  |                                                                                                                                          
  |=============================================================================================================================       |  95%
  |                                                                                                                                          
  |====================================================================================================================================| 100%
h2o.performance(ModelB)
H2ORegressionMetrics: deeplearning
** Reported on training data. **
** Metrics reported on full training frame **

MSE:  77.40097
RMSE:  8.797782
MAE:  6.257931
RMSLE:  NaN
Mean Residual Deviance :  77.40097
# fit models from simplest to more complex
ModelC <- h2o.deeplearning(
  x = names(macd_ML[,1:32]), 
  y = "M_T",
  training_frame = macd_ML,
  activation = "Tanh",
  overwrite_with_best_model = TRUE, 
  autoencoder = FALSE, 
  hidden = c(30,30), 
  loss = "Automatic",
  sparse = TRUE,
  l1 = 1e-4,
  distribution = "AUTO",
  stopping_metric = "MSE",
  #balance_classes = T,
  epochs = 600)

  |                                                                                                                                          
  |                                                                                                                                    |   0%
  |                                                                                                                                          
  |=============                                                                                                                       |  10%
  |                                                                                                                                          
  |====================================================================                                                                |  52%
  |                                                                                                                                          
  |=========================================================================================================================           |  92%
  |                                                                                                                                          
  |====================================================================================================================================| 100%
h2o.performance(ModelC)
H2ORegressionMetrics: deeplearning
** Reported on training data. **
** Metrics reported on full training frame **

MSE:  210.7035
RMSE:  14.51563
MAE:  11.72863
RMSLE:  NaN
Mean Residual Deviance :  210.7035
# fit models from simplest to more complex
ModelD <- h2o.deeplearning(
  x = names(macd_ML[,1:32]), 
  y = "M_T",
  training_frame = macd_ML,
  activation = "Tanh",
  overwrite_with_best_model = TRUE, 
  autoencoder = FALSE, 
  hidden = c(200,100,200), 
  loss = "Automatic",
  sparse = TRUE,
  l1 = 1e-4,
  distribution = "AUTO",
  stopping_metric = "MSE",
  #balance_classes = T,
  epochs = 600)

  |                                                                                                                                          
  |                                                                                                                                    |   0%
  |                                                                                                                                          
  |=========                                                                                                                           |   7%
  |                                                                                                                                          
  |=============                                                                                                                       |  10%
  |                                                                                                                                          
  |==================                                                                                                                  |  13%
  |                                                                                                                                          
  |======================                                                                                                              |  17%
  |                                                                                                                                          
  |==========================                                                                                                          |  20%
  |                                                                                                                                          
  |===============================                                                                                                     |  23%
  |                                                                                                                                          
  |===================================                                                                                                 |  27%
  |                                                                                                                                          
  |==========================================                                                                                          |  32%
  |                                                                                                                                          
  |==============================================                                                                                      |  35%
  |                                                                                                                                          
  |=====================================================                                                                               |  40%
  |                                                                                                                                          
  |=========================================================                                                                           |  43%
  |                                                                                                                                          
  |==============================================================                                                                      |  47%
  |                                                                                                                                          
  |================================================================                                                                    |  48%
  |                                                                                                                                          
  |====================================================================                                                                |  52%
  |                                                                                                                                          
  |=========================================================================                                                           |  55%
  |                                                                                                                                          
  |=============================================================================                                                       |  58%
  |                                                                                                                                          
  |====================================================================================                                                |  63%
  |                                                                                                                                          
  |======================================================================================                                              |  65%
  |                                                                                                                                          
  |==========================================================================================                                          |  68%
  |                                                                                                                                          
  |===============================================================================================                                     |  72%
  |                                                                                                                                          
  |===================================================================================================                                 |  75%
  |                                                                                                                                          
  |=======================================================================================================                             |  78%
  |                                                                                                                                          
  |============================================================================================================                        |  82%
  |                                                                                                                                          
  |================================================================================================================                    |  85%
  |                                                                                                                                          
  |=====================================================================================================================               |  88%
  |                                                                                                                                          
  |=========================================================================================================================           |  92%
  |                                                                                                                                          
  |=============================================================================================================================       |  95%
  |                                                                                                                                          
  |==================================================================================================================================  |  98%
  |                                                                                                                                          
  |====================================================================================================================================| 100%
h2o.performance(ModelD)
H2ORegressionMetrics: deeplearning
** Reported on training data. **
** Metrics reported on full training frame **

MSE:  65.23583
RMSE:  8.07687
MAE:  5.380744
RMSLE:  0.2714364
Mean Residual Deviance :  65.23583

We can also try other parameters in Model A for example computing variables importances (not relevant for this task)

# fit models from simplest to more complex
ModelA <- h2o.deeplearning(
  x = names(macd_ML[,1:32]), 
  y = "M_T",
  training_frame = macd_ML,
  activation = "Tanh",
  overwrite_with_best_model = TRUE, 
  autoencoder = FALSE, 
  hidden = c(100,100), 
  loss = "Automatic",
  sparse = TRUE,
  l1 = 1e-4,
  distribution = "AUTO",
  stopping_metric = "MSE",
  #balance_classes = T,
  variable_importances = T,
  epochs = 600)

  |                                                                                                                                          
  |                                                                                                                                    |   0%
  |                                                                                                                                          
  |=======                                                                                                                             |   5%
  |                                                                                                                                          
  |==================                                                                                                                  |  13%
  |                                                                                                                                          
  |==========================                                                                                                          |  20%
  |                                                                                                                                          
  |===================================                                                                                                 |  27%
  |                                                                                                                                          
  |============================================                                                                                        |  33%
  |                                                                                                                                          
  |=====================================================                                                                               |  40%
  |                                                                                                                                          
  |======================================================================                                                              |  53%
  |                                                                                                                                          
  |========================================================================================                                            |  67%
  |                                                                                                                                          
  |=====================================================================================================                               |  77%
  |                                                                                                                                          
  |===========================================================================================================================         |  93%
  |                                                                                                                                          
  |====================================================================================================================================| 100%

searching hyperparameters

hyper_params <- list(
  activation=c("Rectifier","Tanh","Maxout","RectifierWithDropout","TanhWithDropout","MaxoutWithDropout"),
  hidden=list(c(100,100),c(50,50),c(30,30,30),c(25,25,25,25)),
  input_dropout_ratio=c(0,0.05),
  l1=seq(0,1e-4,1e-6),
  l2=seq(0,1e-4,1e-6)
)

This is the method of finding the best model running it at once: see https://github.com/h2oai/h2o-tutorials/tree/master/tutorials/deeplearning

## Stop once the top 5 models are within 1% of each other (i.e., the windowed average varies less than 1%)
search_criteria = list(strategy = "RandomDiscrete", max_runtime_secs = 360, max_models = 100, seed=1234567, stopping_rounds=5, stopping_tolerance=1e-2)
dl_random_grid <- h2o.grid(
  algorithm="deeplearning",
  #grid_id = "dl_grid_random",
  training_frame=macd_ML,
  x=names(macd_ML[,1:32]), 
  y="M_T",
  epochs=1,
  stopping_metric="MSE",
  stopping_tolerance=1e-2,        ## stop when logloss does not improve by >=1% for 2 scoring events
  stopping_rounds=2,
  score_validation_samples=10000, ## downsample validation set for faster scoring
  score_duty_cycle=0.025,         ## don't score more than 2.5% of the wall time
  max_w2=10,                      ## can help improve stability for Rectifier
  hyper_params = hyper_params,
  search_criteria = search_criteria
)                                
grid <- h2o.getGrid("dl_grid_random",sort_by="MSE",decreasing=FALSE)
grid

… need time to study this result, isn’t it???

Let’s try to predict?

Let’s assume we have the latest information… what will the model will say?

plot(macd_latest[1, 1:32])
Error in plot.new() : figure margins too large

What about Classification Model?

In case our model will have a categorical variable as a label we can attempt to go for classification modelling

I would then re-create dataset by transforming to categorical variables

ModelCA <- h2o.deeplearning(
  x = names(macd_Cat[,1:32]), 
  y = "M_T",
  training_frame = macd_Cat,
  activation = "Tanh",
  overwrite_with_best_model = TRUE, 
  autoencoder = FALSE, 
  hidden = c(100,100), 
  loss = "Automatic",
  sparse = TRUE,
  l1 = 1e-4,
  distribution = "AUTO",
  stopping_metric = "AUTO",
  #balance_classes = T,
  #variable_importances = T,
  epochs = 600)

  |                                                                                                                                          
  |                                                                                                                                    |   0%
  |                                                                                                                                          
  |====                                                                                                                                |   3%
  |                                                                                                                                          
  |====================                                                                                                                |  15%
  |                                                                                                                                          
  |===============================                                                                                                     |  23%
  |                                                                                                                                          
  |==========================================                                                                                          |  32%
  |                                                                                                                                          
  |=======================================================                                                                             |  42%
  |                                                                                                                                          
  |====================================================================                                                                |  52%
  |                                                                                                                                          
  |===============================================================================                                                     |  60%
  |                                                                                                                                          
  |===============================================================================================                                     |  72%
  |                                                                                                                                          
  |============================================================================================================                        |  82%
  |                                                                                                                                          
  |===========================================================================================================================         |  93%
  |                                                                                                                                          
  |====================================================================================================================================| 100%
summary(ModelCA)
Model Details:
==============

H2OMultinomialModel: deeplearning
Model Key:  DeepLearning_model_R_1522269773579_1 
Status of Neuron Layers: predicting M_T, 6-class classification, multinomial distribution, CrossEntropy loss, 14,006 weights/biases, 172.7 KB, 183,000 training samples, mini-batch size 1
  layer units    type dropout       l1       l2 mean_rate rate_rms momentum mean_weight weight_rms mean_bias bias_rms
1     1    32   Input  0.00 %                                                                                        
2     2   100    Tanh  0.00 % 0.000100 0.000000  0.051910 0.176526 0.000000    0.013192   0.222632  0.017851 0.306225
3     3   100    Tanh  0.00 % 0.000100 0.000000  0.038969 0.029415 0.000000    0.001196   0.147001  0.017889 0.385062
4     4     6 Softmax         0.000100 0.000000  0.069184 0.091559 0.000000   -0.016573   0.853892 -2.322938 1.100623

H2OMultinomialMetrics: deeplearning
** Reported on training data. **
** Metrics reported on full training frame **

Training Set Metrics: 
=====================

Extract training frame with `h2o.getFrame("macd_Cat")`
MSE: (Extract with `h2o.mse`) 0.1307116
RMSE: (Extract with `h2o.rmse`) 0.3615405
Logloss: (Extract with `h2o.logloss`) 0.4384951
Mean Per-Class Error: 0.3162548
Confusion Matrix: Extract with `h2o.confusionMatrix(<model>,train = TRUE)`)
=========================================================================
Confusion Matrix: Row labels: Actual class; Column labels: Predicted class
       five four one six tree two  Error       Rate
five     65    0   3   3    0   0 0.0845 =   6 / 71
four      4    8   2   6    4   0 0.6667 =  16 / 24
one       1    0  41   1    1   0 0.0682 =   3 / 44
six       0    0   5  78    4   0 0.1034 =   9 / 87
tree      0    0   2   1   62   0 0.0462 =   3 / 65
two       2    0   3   7    1   1 0.9286 =  13 / 14
Totals   72    8  56  96   72   1 0.1639 = 50 / 305

Hit Ratio Table: Extract with `h2o.hit_ratio_table(<model>,train = TRUE)`
=======================================================================
Top-6 Hit Ratios: 
  k hit_ratio
1 1  0.836066
2 2  0.931148
3 3  0.977049
4 4  0.993443
5 5  1.000000
6 6  1.000000





Scoring History: 
            timestamp   duration training_speed    epochs iterations       samples training_rmse training_logloss
1 2018-03-28 22:47:48  0.000 sec                  0.00000          0      0.000000                               
2 2018-03-28 22:47:48  0.768 sec   6434 obs/sec  10.00000          1   3050.000000       0.87105          4.56768
3 2018-03-28 22:47:54  5.818 sec  11062 obs/sec 200.00000         20  61000.000000       0.52269          1.10962
4 2018-03-28 22:47:59 10.977 sec  12020 obs/sec 420.00000         42 128100.000000       0.51351          0.85628
5 2018-03-28 22:48:03 15.158 sec  12339 obs/sec 600.00000         60 183000.000000       0.36154          0.43850
  training_classification_error
1                              
2                       0.80656
3                       0.33770
4                       0.32787
5                       0.16393

Variable Importances: (Extract with `h2o.varimp`) 
=================================================

Variable Importances: 
  variable relative_importance scaled_importance percentage
1      X32            1.000000          1.000000   0.062053
2       X2            0.939487          0.939487   0.058298
3       X3            0.784664          0.784664   0.048691
4      X31            0.654149          0.654149   0.040592
5       X4            0.597804          0.597804   0.037095

---
   variable relative_importance scaled_importance percentage
27      X14            0.396537          0.396537   0.024606
28      X29            0.391979          0.391979   0.024323
29      X22            0.370001          0.370001   0.022960
30       X7            0.356184          0.356184   0.022102
31       X1            0.348629          0.348629   0.021633
32      X10            0.339044          0.339044   0.021039

Let’s try to predict?

Let’s assume we have the latest information… what will the model will say?

macd_latest <- macd_ML2[200, NA] #label = five
Error in `[.data.frame`(macd_ML2, 200, NA) : undefined columns selected
pred200$predict
[1] five
Levels: five
# more trials
ModelCA1 <- h2o.deeplearning(
  x = names(macd_Cat[,1:32]), 
  y = "M_T",
  training_frame = macd_Cat,
  activation = "Tanh",
  overwrite_with_best_model = TRUE, 
  autoencoder = FALSE, 
  hidden = c(200,200), 
  loss = "Automatic",
  sparse = TRUE,
  l1 = 1e-4,
  distribution = "AUTO",
  stopping_metric = "AUTO",
  #balance_classes = T,
  #variable_importances = T,
  epochs = 600)

  |                                                                                                                                          
  |                                                                                                                                    |   0%
  |                                                                                                                                          
  |====                                                                                                                                |   3%
  |                                                                                                                                          
  |=========                                                                                                                           |   7%
  |                                                                                                                                          
  |===============                                                                                                                     |  12%
  |                                                                                                                                          
  |====================                                                                                                                |  15%
  |                                                                                                                                          
  |========================                                                                                                            |  18%
  |                                                                                                                                          
  |=============================                                                                                                       |  22%
  |                                                                                                                                          
  |=================================                                                                                                   |  25%
  |                                                                                                                                          
  |=====================================                                                                                               |  28%
  |                                                                                                                                          
  |==========================================                                                                                          |  32%
  |                                                                                                                                          
  |==============================================                                                                                      |  35%
  |                                                                                                                                          
  |===================================================                                                                                 |  38%
  |                                                                                                                                          
  |=======================================================                                                                             |  42%
  |                                                                                                                                          
  |===========================================================                                                                         |  45%
  |                                                                                                                                          
  |================================================================                                                                    |  48%
  |                                                                                                                                          
  |====================================================================                                                                |  52%
  |                                                                                                                                          
  |=========================================================================                                                           |  55%
  |                                                                                                                                          
  |=============================================================================                                                       |  58%
  |                                                                                                                                          
  |=================================================================================                                                   |  62%
  |                                                                                                                                          
  |======================================================================================                                              |  65%
  |                                                                                                                                          
  |==========================================================================================                                          |  68%
  |                                                                                                                                          
  |===============================================================================================                                     |  72%
  |                                                                                                                                          
  |=======================================================================================================                             |  78%
  |                                                                                                                                          
  |============================================================================================================                        |  82%
  |                                                                                                                                          
  |================================================================================================================                    |  85%
  |                                                                                                                                          
  |=====================================================================================================================               |  88%
  |                                                                                                                                          
  |=========================================================================================================================           |  92%
  |                                                                                                                                          
  |=============================================================================================================================       |  95%
  |                                                                                                                                          
  |==================================================================================================================================  |  98%
  |                                                                                                                                          
  |====================================================================================================================================| 100%
summary(ModelCA1)
Model Details:
==============

H2OMultinomialModel: deeplearning
Model Key:  DeepLearning_model_R_1522269773579_5 
Status of Neuron Layers: predicting M_T, 6-class classification, multinomial distribution, CrossEntropy loss, 48,006 weights/biases, 573.5 KB, 183,000 training samples, mini-batch size 1
  layer units    type dropout       l1       l2 mean_rate rate_rms momentum mean_weight weight_rms mean_bias bias_rms
1     1    32   Input  0.00 %                                                                                        
2     2   200    Tanh  0.00 % 0.000100 0.000000  0.097310 0.202946 0.000000    0.000910   0.164691  0.012524 0.209276
3     3   200    Tanh  0.00 % 0.000100 0.000000  0.105784 0.181197 0.000000   -0.000612   0.070102  0.005249 0.422971
4     4     6 Softmax         0.000100 0.000000  0.119109 0.194559 0.000000   -0.016467   0.564256 -2.093254 1.284491

H2OMultinomialMetrics: deeplearning
** Reported on training data. **
** Metrics reported on full training frame **

Training Set Metrics: 
=====================

Extract training frame with `h2o.getFrame("macd_Cat")`
MSE: (Extract with `h2o.mse`) 0.1719866
RMSE: (Extract with `h2o.rmse`) 0.4147127
Logloss: (Extract with `h2o.logloss`) 0.629889
Mean Per-Class Error: 0.3891719
Confusion Matrix: Extract with `h2o.confusionMatrix(<model>,train = TRUE)`)
=========================================================================
Confusion Matrix: Row labels: Actual class; Column labels: Predicted class
       five four one six tree two  Error       Rate
five     63    0   6   2    0   0 0.1127 =   8 / 71
four      3    1   7   6    7   0 0.9583 =  23 / 24
one       2    0  42   0    0   0 0.0455 =   2 / 44
six       0    0   7  72    8   0 0.1724 =  15 / 87
tree      1    0   2   0   62   0 0.0462 =   3 / 65
two       2    0   4   7    1   0 1.0000 =  14 / 14
Totals   71    1  68  87   78   0 0.2131 = 65 / 305

Hit Ratio Table: Extract with `h2o.hit_ratio_table(<model>,train = TRUE)`
=======================================================================
Top-6 Hit Ratios: 
  k hit_ratio
1 1  0.786885
2 2  0.901639
3 3  0.960656
4 4  0.996721
5 5  1.000000
6 6  1.000000





Scoring History: 
             timestamp   duration training_speed    epochs iterations       samples training_rmse training_logloss
1  2018-03-28 23:03:49  0.000 sec                  0.00000          0      0.000000                               
2  2018-03-28 23:03:50  0.767 sec   4265 obs/sec  10.00000          1   3050.000000       0.89639          5.61147
3  2018-03-28 23:03:55  5.934 sec   4677 obs/sec  90.00000          9  27450.000000       0.76439          2.72534
4  2018-03-28 23:04:01 11.223 sec   4652 obs/sec 170.00000         17  51850.000000       0.58810          1.61467
5  2018-03-28 23:04:06 16.510 sec   4644 obs/sec 250.00000         25  76250.000000       0.54758          1.10819
6  2018-03-28 23:04:11 21.737 sec   4652 obs/sec 330.00000         33 100650.000000       0.45845          0.90001
7  2018-03-28 23:04:16 26.906 sec   4668 obs/sec 410.00000         41 125050.000000       0.56910          1.14495
8  2018-03-28 23:04:22 32.252 sec   4652 obs/sec 490.00000         49 149450.000000       0.42358          0.69182
9  2018-03-28 23:04:27 37.521 sec   4651 obs/sec 570.00000         57 173850.000000       0.41471          0.62989
10 2018-03-28 23:04:29 39.556 sec   4645 obs/sec 600.00000         60 183000.000000       0.59947          1.43570
11 2018-03-28 23:04:29 39.572 sec   4645 obs/sec 600.00000         60 183000.000000       0.41471          0.62989
   training_classification_error
1                               
2                        0.82623
3                        0.64262
4                        0.40000
5                        0.36393
6                        0.23934
7                        0.37377
8                        0.20000
9                        0.21311
10                       0.40656
11                       0.21311

Variable Importances: (Extract with `h2o.varimp`) 
=================================================

Variable Importances: 
  variable relative_importance scaled_importance percentage
1      X32            1.000000          1.000000   0.063955
2       X2            0.974053          0.974053   0.062295
3       X3            0.696651          0.696651   0.044554
4       X1            0.636150          0.636150   0.040685
5       X4            0.605534          0.605534   0.038727

---
   variable relative_importance scaled_importance percentage
27       X5            0.357844          0.357844   0.022886
28      X22            0.357326          0.357326   0.022853
29      X30            0.354696          0.354696   0.022685
30      X13            0.353810          0.353810   0.022628
31      X29            0.329508          0.329508   0.021074
32      X27            0.325776          0.325776   0.020835

There are pretty different results… potentially the error rate is high!

h2o.performance(ModelCA1)
H2OMultinomialMetrics: deeplearning
** Reported on training data. **
** Metrics reported on full training frame **

Training Set Metrics: 
=====================

Extract training frame with `h2o.getFrame("macd_Cat")`
MSE: (Extract with `h2o.mse`) 0.1719866
RMSE: (Extract with `h2o.rmse`) 0.4147127
Logloss: (Extract with `h2o.logloss`) 0.629889
Mean Per-Class Error: 0.3891719
Confusion Matrix: Extract with `h2o.confusionMatrix(<model>,train = TRUE)`)
=========================================================================
Confusion Matrix: Row labels: Actual class; Column labels: Predicted class
       five four one six tree two  Error       Rate
five     63    0   6   2    0   0 0.1127 =   8 / 71
four      3    1   7   6    7   0 0.9583 =  23 / 24
one       2    0  42   0    0   0 0.0455 =   2 / 44
six       0    0   7  72    8   0 0.1724 =  15 / 87
tree      1    0   2   0   62   0 0.0462 =   3 / 65
two       2    0   4   7    1   0 1.0000 =  14 / 14
Totals   71    1  68  87   78   0 0.2131 = 65 / 305

Hit Ratio Table: Extract with `h2o.hit_ratio_table(<model>,train = TRUE)`
=======================================================================
Top-6 Hit Ratios: 
  k hit_ratio
1 1  0.786885
2 2  0.901639
3 3  0.960656
4 4  0.996721
5 5  1.000000
6 6  1.000000

Save the model

In case we want to save the model persistently we can do so

# shutdown...
h2o.shutdown(prompt = F)
[1] TRUE

Conclusion

This procedure can be repeated for every market period… and hopefully it will bring some fruits…?

Utility Code

Adapting function to_m


# Function converting time series data to matrix
to_m <- function(x, n_cols) {
  ### PURPOSE: Transform Time Series Column of the dataframe to the matrix
  #            with specified number of columns. Number of rows will be automatically
  #            found and remaining data points discarded
  # # Uncomment variable to debug function
  # x -< dataframe with one column
  
  # x <- DF_TEMP
  # n_cols <- 150
  
  # get intermediate object and dimension
  Step1 <- x
  # find number of rows of data frame
  nrows <- Step1 %>% nrow()
  # find the number of row in a matrix (Whole Rows), the value will have decimals...
  WN <- nrows/n_cols
  ## extract the whole number uncomment for debug/test
  # WN <- 19.2
  # WN <- 19.8
  if((WN - round(WN)) < 0){WN <- round(WN) - 1} else {WN <- round(WN)}
  # find number of rows to extract data
  n <- n_cols * WN
  # extract relevant matrix
  Step2 <- Step1 %>% 
    head(n) %>% #only use whole number to avoid errors
    t() %>%  # this brings us a matrix
    matrix(nrow = WN, ncol = n_cols, byrow = TRUE) # transforming that into matrix size 20x150
  # return the result of the function
  return(Step2)
}

Install fresh copy of h2o

See www.h2o.ai –> Download –> Install from R

LS0tDQp0aXRsZTogIkRldGVjdCBNYXJrZXQgc3RhdHVzIHdpdGggQUkiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyBQdXJwb3NlDQoNClRoaXMgd29yayBhaW1zIHRvIGRldmVsb3Agc2V0cyBvZiB0b29scyBhbmQgcHJvY2VkdXJlcyB0aGF0IHdpbGwgaGVscCB0cmFkZXIgdG8gZWZmaWNpZW50bHkgZ3Vlc3MgRmluYW5jaWFsIEFzc2V0IE1hcmtldCBUeXBlLiBXaGV0aGVyIGl0J3MgYSBCdWxsaXNoIG9yIEJlYXJpc2ggTWFya2V0LCBSYW5naW5nLCBWb2xhdGlsZSAtIEF1dGhvciBiZWxpZXZlcyB0aGF0IGhhdmluZyB0aGlzIGFiaWxpdHkgdG8gZGV0ZWN0IG1hcmtldCB0eXBlIGFuZCB1c2UgaXQgaW4gdHJhZGluZyB3b3VsZCBiZSBvZiBhIGdyZWF0IGFkdmFudGFnZSENCg0KSW4gb3JkZXIgdG8gdGVzdCB0aGUgYXBwcm9hY2ggc2Vjb25kYXJ5IG1ldGhvZCB3aWxsIGJlIGRldmVsb3BlZC4gVGhhdCBpcyB0byBpZGVudGlmeSBiZXN0ICdlbnRyeScgcGF0dGVybi4NCg0KV2hlbmV2ZXIgdGhpcyBhdHRlbXB0IGZhaWxzLCB0aGVyZSB3b3VsZCBzdGlsbCBiZSBsZWFybmluZyBsZWZ0ISBSZWFkZXIgd291bGQgYmUgc3RpbGwgY2FwYWJsZSB0byBrbm93IGhvdyB0byAqKlVzZSBEZWVwIExlYXJuaW5nIGZvciBSZWdyZXNzaW9uL0NsYXNzaWZpY2F0aW9uIHByb2JsZW1zKioNCg0KIyMgVGFzayBvdXRsYXkNCg0KQmFzaWMgaWRlYSBvZiBhY2hpZXZlaW5nIHRoaXMgd2lsbCBiZToNCg0KLSBNYW51YWxseSBjbGFzc2lmeSBkYXRhIGZyb20gZm9yZXggcGFpcnMgaW50byBwZXJpb2RzIG9mIHNwZWNpZmljIG1hcmtldCBwZXJpb2RzDQotIEV4dHJhY3QgTUFDRCBpbmRpY2F0b3IgKG9yIGFueSBvdGhlciBpbmRpY2F0b3IpIGNvcnJlc3BvbmRpbmcgdG8gdGhlIHBlcmlvZHMNCi0gQ3JlYXRlIGNvbWJpbmVkIGRhdGFzZXQgd2l0aCBjbGFzc2lmaWVkIGRhdGENCi0gRml0IHJlZ3Jlc3Npb24gTk4gbW9kZWwNCi0gUHJvZHVjdGlvbml6ZSBtb2RlbCBmb3IgdGhlIG5ldyBjb21pbmcgZGF0YSENCi0gSW4gTVFMIHNpZGU6DQogICAgLSBzZXQgZmxhZ3MgKGUuZy4gYnVsbGlzaDogc2VsbCA9IEZhbHNlKQ0KICAgIC0gZmluZSB0dW5lIHBhcmFtZXRlcnMuIChlLmcuIHNldCB1cCBzcGVjaWZpYyBtYXJrZXQgcGVyaW9kIGFuZCBmaW5kIHBhcmFtZXRlcnMgYnkgdXNpbmcgb3B0aW1pemF0aW9uKQ0KLSBSZXF1aXJlZCB0byByZWFkIHRpbWUgc2VyaWVzIGRhdGEsIHZpc3VhbGl6ZSBpdCBhcyB0aW1lLXNlcmllcyBkYXRhLCB0cmFuc2Zvcm0gdG8gbWF0cml4LCB2aXN1YWxpemUgYWdhaW4gYXMgM0QsIHRyYWluIHRoZSBtb2RlbC4uLg0KDQojIyBMb2FkIHBhY2thZ2VzDQoNCk5vdGU6IHVzZSBSIHNjcmlwdCBhdHRhY2hlZCB0byB0aGlzIHJlcG9zaXRvcnkgY2FsbGVkOiBgNl9oMm9fSW5zdGFsbC5SYCB0byBpbnN0YWxsIGgybyBvbiB5b3VyIGNvbXB1dGVyDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShoMm8pDQpgYGANCg0KIyMgRGF0YSByZWFkDQoNCkhlcmUgd2UgY2FuIGdldCBpbnRvIHRoZSBmaW5hbmNpYWwgZGF0YS4gRmluYW5jaWFsIGRhdGEgY2FuIGJlIHJlYWQgYW5kIHJlZnJlc2hlZCB1c2luZyBNUUwgc2lkZS4gSG93IHRvIGRvIHRoaXMgaXMgZXhwbGFpbmVkIGluIHRoZSBVZGVteSBjb3Vyc2UuDQpGb3IgdGhlIHJlcHJvZHVjaWJpbGl0eSBwdXJwb3NlcyBhbmQgZm9yIHRob3NlIHdobyBhcmUgbm90IHBsYW5uaW5nIHRvIHRyYWRlIHNhbXBsZSBkYXRhIGlzIGF2YWlsYWJsZSBpbiB0aGUgcmVwb3NpdG9yeToNCg0KYGBge3J9DQojIHBhdGggdG8gYWN0dWFsIHByaWNlcw0KUGF0aF9UMiA8LSAiQzovUHJvZ3JhbSBGaWxlcyAoeDg2KS9GeFBybyAtIFRlcm1pbmFsMi9NUUw0L0ZpbGVzLyINCiMgbG9hZCBwcmljZXMgb2YgMjggY3VycmVuY2llcw0KcHJpY2VzIDwtIHJlYWRfY3N2KGZpbGUucGF0aChQYXRoX1QyLCAiQUlfQ1AxNS5jc3YiKSwgY29sX25hbWVzID0gRikNCnByaWNlcyA8LSByZWFkX2NzdigiQUlfQ1AxNS5jc3YiLCBjb2xfbmFtZXMgPSBGKQ0KcHJpY2VzJFgxIDwtIHltZF9obXMocHJpY2VzJFgxKQ0KIyBsb2FkIG1hY2QgaW5kaWNhdG9yIG9mIDI4IGN1cnJlbmNpZXMNCm1hY2QgPC0gcmVhZF9jc3YoZmlsZS5wYXRoKFBhdGhfVDIsICJBSV9NYWNkMTUuY3N2IiksIGNvbF9uYW1lcyA9IEYpDQojIHVzZSB0aGlzIG9wdGlvbiB0byB1c2Ugc2FtcGxlIGRhdGE6DQptYWNkIDwtIHJlYWRfY3N2KCJBSV9NYWNkMTUuY3N2IiwgY29sX25hbWVzID0gRikNCm1hY2QkWDEgPC0geW1kX2htcyhtYWNkJFgxKQ0KYGBgDQoNCiMjIENhdGNoaW5nIHNwZWNpZmljIG1hcmtldCBwZXJpb2RzDQoNCkhlcmUgd2Ugd291bGQgbmVlZCB0byBtYW51YWxseSBjaGFuZ2UgWSB2YXJpYWJsZSBpbiB0aGUgcGxvdCB1bnRpbCBmaW5kaW5nIHNpdXRhYmxlIG1hcmtldCBjb25kaXRpb24uLi4NCg0KMS4gQnVsbCBub3JtYWwNCjIuIEJ1bGwgdm9sYXRpbGUNCjMuIEJlYXIgbm9ybWFsDQo0LiBCZWFyIHZvbGF0aWxlDQo1LiBTaWRld2F5cyBxdWlldA0KNi4gU2lkZXdheXMgdm9sYXRpbGUNCg0KVGhpcyBpcyAnbWFudWFsJyBwYXJ0IG9mIHRoaW5ncyB3aXRoIGEgY2hhbmNlIG9mIGJpYXMuIEZlbGxvdyByZWFkZXIgY2FuIGNlcnRhaW5seSBjcmVhdGUgY3VzdG9tIGZ1bmN0aW9ucyB0byBzZWxlY3QgcGVyaW9kcyBhdXRvbWF0aWNhbGx5LiBBdXRob3Igb2YgdGhpcyB0ZXh0IGlzIHRvbyBsYXp5IHRvIGRvIHRoYXQgYW5kIHRydXN0IG1vcmUgdG8gdGhlIHBlcnNvbmFsIGJyYWluIHRvIGRvIHNvDQoNCiMjIyBFeGFtcGxlIG9mIGRhdGEgc2VsZWN0aW9uIGZvciBvbmUgTWFya2V0IFR5cGU6IEJ1bGwgbm9ybWFsDQoNCkNvZGUgYmVsb3cgd2lsbCBjcmVhdGUgdGltZS1zZXJpZXMgcGxvdCBvZiBvbmUgY3VycmVuY3kgcGFpcg0KDQpgYGB7cn0NCmdncGxvdChwcmljZXMsIGFlcyhYMSwgWDMpKStnZW9tX2xpbmUoKQ0KYGBgDQoNCldlIHdpbGwgZXh0cmFjdCBvbmx5IGNvcnJlc3BvbmRpbmcgcGllY2UgaW4gdGhpcyBjYXNlIHN0YXJ0aW5nIGZyb20gTm92ZW1iZXInMjAxNy4uLg0KDQpgYGB7cn0NCiMgZXh0cmFjdCBhcHByb3hpbWF0ZSBkYXRlIGFuZCBjaG9vc2Ugb25seSByZWxldmFudCBjb2x1bW5zDQpidWxsX25vcm0gPC0gcHJpY2VzICU+JSBmaWx0ZXIoWDEgPiAiMjAxNy0xMS0wNSIsIFgxIDwgIjIwMTctMTEtMjUiKSAlPiUgc2VsZWN0KFgxLCBYMykNCmBgYA0KDQouLi4gYW5kIHZpc3VhbGl6ZSBpdCB0byBjb25maXJtIA0KDQpgYGB7cn0NCmdncGxvdChidWxsX25vcm0sIGFlcyhYMSwgWDMpKStnZW9tX2xpbmUoKQ0KYGBgDQoNCm5leHQsIHdlIGNhbiBleHRyYWN0IGNvcnJlc3BvbmRpbmcgcGllY2Ugb2YgYG1hY2RgIGRhdGFmcmFtZToNCg0KYGBge3J9DQptYWNkX2J1bGxfbm9ybSA8LSBtYWNkICU+JSBzZWxlY3QoWDEsIFgzKSAlPiUgaW5uZXJfam9pbihidWxsX25vcm0sIGJ5ID0gYygiWDEiID0gIlgxIikpDQpgYGANCg0KYW5kIHZpc3VhbGl6ZSBib3RoIHRoaW5ncyB0b2dldGhlcg0KDQpgYGB7cn0NCmdncGxvdChtYWNkX2J1bGxfbm9ybSwgYWVzKFgxLCBYMy55LCBjb2wgPSBYMy54KSkrZ2VvbV9saW5lKCkNCmBgYA0KDQpsZXQncyBub3cgdXNlIHRoaXMgZnVuY3Rpb246DQoNCmBgYHtyfQ0KbWFjZF9tX2J1bGxfbm9ybSA8LSBtYWNkX2J1bGxfbm9ybSAlPiUgc2VsZWN0KFgzLngpICU+JSB0b19tKDEwMCkNCmBgYA0KDQouLi50byBjb252ZXJ0IHRoaXMgZGF0YXNldCB0byB0aGUgbWF0cml4IHdpdGggMTAwIGNvbHVtbnMNCg0KIyMjIFZpc3VhbGl6ZSBuZXcgbWF0cml4IGluIDNEDQoNCmFuZCBub3cgd2UgY2FuIGBzZWVgIHRoZSBvYnRhaW5lZCBzdXJmYWNlIGFzIDNEIHBsb3QuIEluIHRoaXMgY2FzZSB3ZSBoYXZlIDE0IHJvd3MuIEVhY2ggb2YgdGhlc2Ugcm93cyB3aWxsIGNvbnRhaW4gMTAwIGRhdGFwb2ludHMNClRpcDogdHJ5IHRvIHJvdGF0ZSBvYnRhaW5lZCBvYmplY3QgYW5kIG5vdGljZSB0aGF0IG1ham9yaXR5IG9mIHBvaW50cyBhcmUgbG9jYXRlZCBpbiB0aGUgcG9zaXRpdmUgYXJlYS4gT2YgY291cnNlIHRoZXJlIHdlcmUgYWxzbyAnY29ycmVjdGlvbnMnIGhlbmNlIHNvbWUgcm93cyBhcmUgaW4gdGhlIG5lZ2F0aXZlIHNpZGUuLi4NCg0KYGBge3J9DQpwbG90X2x5KHogPSBtYWNkX21fYnVsbF9ub3JtLCB0eXBlID0gInN1cmZhY2UiKQ0KYGBgDQoNCkJyaWVmIGV4cGxhbmF0aW9uIGlzIHByb2JhYmx5IHJlcXVpcmVkLiBXaHkgZG8gd2UgdXNlIDEwMCBkYXRhcG9pbnRzIChvciBsZXNzKSBpbiBvbmUgcm93PyBUaGUgbWVhbmluZyBvZiB0aG9zZSB3aWxsIGJlIHRvIGdpdmUgdXNlIHRoZSBwYXR0ZXJuIG9yIGZpbmdlcnByaW50IG9mIHRoYXQgb25lIHNwZWNpZmljIG1hcmtldCBwZXJpb2QuIFRoZSBnb2FsIG9mIG91ciBtb2RlbCBsYXRlciB3aWxsIGJlIGV4YWN0bHkgdGhpcy4gVG8gZGlnZXN0IHRoZSBsYXN0IG9ic2VydmF0aW9ucyB0aHJvdWdoIHRoZSBtb2RlbCBhbmQgb3V0cHV0IHRoZSB2YWx1ZSBvciBjYXRlZ29yeSBoZW5jZSByZWNvZ25pemluZyB3aGF0IGlzIHRoZSBzcGVjaWZpYyBtYXJrZXQgdHlwZS4uLg0KDQpMZXQncyBob3dldmVyIG1ha2Ugc29tZSBtb3JlIGNvbnNpZGVyYXRpb25zLiBXaHkgZG9uJ3Qgd2Ugc2F5IHRvIGd1ZXNzIG91ciBtYXJrZXQgdHlwZSBkZWNpc2lvbiBvbiB0aGUgbGFzdCA4IGhvdXJzIGhlbmNlIDgqNjAvMTUgd2hpY2ggd2lsbCByZXN1bHQgMzIgTTE1IGJhcnM6DQoNCmBgYHtyfQ0KbWFjZF9tX2J1bGxfbm9ybSA8LSBtYWNkX2J1bGxfbm9ybSAlPiUgc2VsZWN0KFgzLngpICU+JSB0b19tKDMyKQ0KcGxvdF9seSh6ID0gbWFjZF9tX2J1bGxfbm9ybSwgdHlwZSA9ICJzdXJmYWNlIikNCg0KYGBgDQoNCldlIGhhdmUgc2VlbiB0aGF0IHRoZSBtYWpvcml0eSBvZiBvdXIgb2JzZXJ2YXRpb25zIGFyZSBpbiB0aGUgJ3Bvc2l0aXZlJyBhcmVhLCBob3dldmVyIHNvbWUgb2YgdGhlIG9ic2VydmF0aW9ucyBkbyBub3QhIEZvciB0aGF0IHJlYXNvbiBpdCB3b3VsZCBiZSBtdWNoIGJldHRlciBwZXJoYXBzIHJlbW92ZSB0aG9zZSBvYnNlcnZhdGlvbnMgdGhhdCBhcmUgbm90IHVwIHRvIG91ciBwYXR0ZXJuISBXaHkgbm90IHRvIHRyeSBEZWVwIExlYXJuaW5nIEF1dG9lbmNvZGVycz8NCg0KIyMjIHdoYXQgYWJvdXQgdW5zdXBlcnZpc2VkIGxlYXJuaW5nPw0KDQpUaGUga2V5IGlkZWEgbm93IHdpbGwgYmUgdG8gdHJhaW4gRGVlcCBMZWFybmluZyBhdXRvZW5jb2RlciBtb2RlbCBvbiB0aGF0IHNlbGVjdGVkIGRhdGFzZXQuIFdlIHdpbGwgJ3NlbmQnIHRoaXMgZGF0YXNldCB0byBvdXIgSlZNOg0KDQpgYGB7cn0NCiMgc3RhcnQgaDJvIHZpcnR1YWwgbWFjaGluZQ0KaDJvLmluaXQoKQ0KIyBsb2FkIGRhdGEgaW50byBoMm8gZW52aXJvbm1lbnQNCm1hY2RfYnYgIDwtIGFzLmgybyh4ID0gbWFjZF9tX2J1bGxfbm9ybSwgZGVzdGluYXRpb25fZnJhbWUgPSAibWFjZF9idWxsX25vcm0iKQ0KYGBgDQoNClRoZW4gd2Ugd2lsbCBmaXQgdGhlIG1vZGVsOg0KDQpgYGB7cn0NCiMgZml0IHRoZSBtb2RlbA0KZGVlcG5ldF9tb2RlbCA8LSBoMm8uZGVlcGxlYXJuaW5nKA0KIHggPSBuYW1lcyhtYWNkX2J2KSwgDQogdHJhaW5pbmdfZnJhbWUgPSBtYWNkX2J2LCANCiBhY3RpdmF0aW9uID0gIlRhbmgiLCANCiBhdXRvZW5jb2RlciA9IFRSVUUsIA0KIGhpZGRlbiA9IGMoMjAsOCwyMCksIA0KIHNwYXJzZSA9IFRSVUUsDQogbDEgPSAxZS00LCANCiBlcG9jaHMgPSAxMDApDQpgYGANCg0KQW55IHRpbWUgbmVlZCB0byBtYWtlIGEgcGF1c2U/DQoNCmBgYHtyfQ0KI2gyby5zaHV0ZG93bihwcm9tcHQgPSBGKQ0KYGBgDQoNCldlIGNhbiBub3cgdXNlIHRoaXMgbW9kZWwgdG8gZXh0cmFjdCBhbm9tYWxvdXMgcmVjb3Jkcy4gUmVjb3JkcyB0aGF0IHdvdWxkIG5vdCBiZSBjb3JyZXNwb25kaW5nIHRvIG91ciAnYnVsbGlzaCcgcGF0dGVybiB3aWxsIGhhdmUgaGlnaGVyIG1zZSB2YWx1ZSwgZm9yIGV4YW1wbGU6IA0KDQpgYGB7cn0NCiMgY2hlY2sgbXNlDQptb2RfZXJyb3IgPC0gaDJvLmFub21hbHkoZGVlcG5ldF9tb2RlbCwgbWFjZF9idikgJT4lIGFzLmRhdGEuZnJhbWUoKQ0KDQptb2RfZXJyb3IgJT4lIHBsb3QudHMoKQ0KI21vZF9lcnJvciAlPiUgc3VtbWFyaXNlKG1lYW5fbXNlID0gbWVhbihSZWNvbnN0cnVjdGlvbi5NU0UpKQ0KYGBgDQoNCldlIG5vdyBjYW4gZmluZCBpbmRleGVzIG9mIG9ic2VydmF0aW9ucyB3aGVyZSBtc2UgZXJyb3IgaXMgaGlnaGVyIHRoYW4gMC4wMDUNCg0KYGBge3J9DQpyb3dfb3V0bGllcnMgPC0gd2hpY2gobW9kX2Vycm9yID4gMC4wMDUpDQpyb3dfY2xlYW5lZCAgPC0gd2hpY2gobW9kX2Vycm9yIDwgMC4wMDUpDQptYWNkX21fYnVsbF9ub3JtX2ZpbHQgPC0gbWFjZF9tX2J1bGxfbm9ybVtyb3dfY2xlYW5lZCwgXQ0KbWFjZF9tX2J1bGxfbm9ybV9vdXRsIDwtIG1hY2RfbV9idWxsX25vcm1bcm93X291dGxpZXJzLCBdDQpgYGANCg0KRmluYWxseSBsZXQncyB0cnkgdG8gc2VlIGlmIHdlIGNvdWxkIG5vdyBmaWx0ZXIgdGhlIG91dGxpZXJzOg0KDQpgYGB7cn0NCiMgb3V0bGllcnMgKG5vdCBidWxsaXNoKQ0KcGxvdF9seSh6ID0gbWFjZF9tX2J1bGxfbm9ybV9vdXRsLCB0eXBlID0gInN1cmZhY2UiKQ0KYGBgDQoNCjggb2JzZXJ2YXRpb25zIHdlcmUgZmlsdGVyZWQuLi4NCg0KYGBge3J9DQojIGZpbHRlcmVkICgnb25seScgYnVsbGlzaCkNCnBsb3RfbHkoeiA9IG1hY2RfbV9idWxsX25vcm1fZmlsdCwgdHlwZSA9ICJzdXJmYWNlIikNCmBgYA0KDQpXZWxsIGl0IHNlZW1zIHRoYXQgd2UgY291bGQgZmlsdGVyIG91ciBvYnNlcnZhdGlvbnMgYnV0IG5vdCBjb21wbGV0ZWx5LiBCZXNpZGVzLCBpdCBpcyBwcm9iYWJseSBxdWVzdGlvbmFibGUgaWYgd2Ugc2hvdWxkIGRvIHRoYXQgaW4gdGhlIGZpcnN0IHBsYWNlLi4uDQoNCk5leHQgd2UgY2FuIGNyZWF0ZSBhIGNvZGUgdGhhdCB3aWxsIGhlbHAgdG8gc2VsZWN0IGRhdGEgZm9yIGV2ZXJ5IG1hcmtldCB0eXBlIGFuZCBjb21iaW5lIHRoYXQgdG8gb25lIHNwZWNpZmljIGRhdGFmcmFtZQ0KDQpgYGB7cn0NCiMjIyMgTWFudWFsbHkgU2VsZWN0aW5nIGRhdGEuLi4gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBNYXJrZXQgUGVyaW9kcw0KIyAxLiBCdWxsIG5vcm1hbA0KIyAyLiBCdWxsIHZvbGF0aWxlDQojIDMuIEJlYXIgbm9ybWFsDQojIDQuIEJlYXIgdm9sYXRpbGUNCiMgNS4gU2lkZXdheXMgcXVpZXQNCiMgNi4gU2lkZXdheXMgdm9sYXRpbGUNCiMgQ2hvb3NlIHRoZSBhc3NldCBjb3JyZXNwb25kaW5nIHRvIHRoaXMgcGVyaW9kIC9maW5kIGJ5IHJlcGxhY2luZyAneScgYXJndW1lbnQvDQpnZ3Bsb3QocHJpY2VzLCBhZXMoWDEsIFgzKSkrZ2VvbV9saW5lKCkNCg0KIyBFeHRyYWN0IGFwcHJveGltYXRlIGRhdGUgYW5kIGNob29zZSBvbmx5IHJlbGV2YW50IGNvbHVtbnMNCnByaWNlX2RmIDwtIHByaWNlcyAlPiUgZmlsdGVyKFgxID4gIjIwMTctMTEtMDUiLCBYMSA8ICIyMDE3LTExLTI1IikgJT4lIHNlbGVjdChYMSwgWDMpDQoNCiMgVmlzdWFsaXplIGl0IHRvIGNvbmZpcm0gDQpnZ3Bsb3QocHJpY2VfZGYsIGFlcyhYMSwgWDMpKStnZW9tX2xpbmUoKQ0KDQojIEV4dHJhY3QgY29ycmVzcG9uZGluZyBwaWVjZSBvZiBtYWNkIGRhdGFmcmFtZToNCm1hY2RfZGYgPC0gbWFjZCAlPiUgc2VsZWN0KFgxLCBYMykgJT4lIGlubmVyX2pvaW4ocHJpY2VfZGYsIGJ5ID0gYygiWDEiID0gIlgxIikpDQoNCiMgVmlzdWFsaXplIGJvdGggdGhpbmdzIHRvZ2V0aGVyDQpnZ3Bsb3QobWFjZF9kZiwgYWVzKFgxLCBYMy55LCBjb2wgPSBYMy54KSkrZ2VvbV9saW5lKCkNCg0KIyB0cmFuc2Zvcm0gdG8gbWF0cml4LCBudW1iZXIgb2YgY29sdW1ucyB3aWxsIGNvcnJlc3BvbmQgdG8gbW9kZWwgc2Vuc2l0aXZpdHkgZS5nLiAxMDAgY29sdW1ucyB+IDI0IEhvdXJzDQoNCm1hY2RfbSA8LSBtYWNkX2RmICU+JSBzZWxlY3QoWDMueCkgJT4lIHRvX20oMzIpDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KIyBhZGQgbmV3IGNvbHVtbiB0byB0aGlzIG1hdHJpeCB3aXRoIHZhbHVlIDENCm1hY2RfbV8xIDwtIHRyYW5zZm9ybShtYWNkX20sIE1fVCA9IDEwKQ0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQojIENob29zZSB0aGUgYXNzZXQgY29ycmVzcG9uZGluZyB0byB0aGlzIHBlcmlvZCAvZmluZCBieSByZXBsYWNpbmcgJ3knIGFyZ3VtZW50Lw0KZ2dwbG90KHByaWNlcywgYWVzKFgxLCBYNCkpK2dlb21fbGluZSgpDQoNCiMgRXh0cmFjdCBhcHByb3hpbWF0ZSBkYXRlIGFuZCBjaG9vc2Ugb25seSByZWxldmFudCBjb2x1bW5zDQpwcmljZV9kZiA8LSBwcmljZXMgJT4lIGZpbHRlcihYMSA+ICIyMDE3LTEwLTAyIiwgWDEgPCAiMjAxNy0xMC0wNyIpICU+JSBzZWxlY3QoWDEsIFg0KQ0KDQojIFZpc3VhbGl6ZSBpdCB0byBjb25maXJtIA0KZ2dwbG90KHByaWNlX2RmLCBhZXMoWDEsIFg0KSkrZ2VvbV9saW5lKCkNCg0KIyBFeHRyYWN0IGNvcnJlc3BvbmRpbmcgcGllY2Ugb2YgbWFjZCBkYXRhZnJhbWU6DQptYWNkX2RmIDwtIG1hY2QgJT4lIHNlbGVjdChYMSwgWDQpICU+JSBpbm5lcl9qb2luKHByaWNlX2RmLCBieSA9IGMoIlgxIiA9ICJYMSIpKQ0KDQojIFZpc3VhbGl6ZSBib3RoIHRoaW5ncyB0b2dldGhlcg0KZ2dwbG90KG1hY2RfZGYsIGFlcyhYMSwgWDQueSwgY29sID0gWDQueCkpK2dlb21fbGluZSgpDQoNCiMgdHJhbnNmb3JtIHRvIG1hdHJpeCwgbnVtYmVyIG9mIGNvbHVtbnMgd2lsbCBjb3JyZXNwb25kIHRvIG1vZGVsIHNlbnNpdGl2aXR5IGUuZy4gMTAwIGNvbHVtbnMgfiAyNCBIb3Vycw0KbWFjZF9tIDwtIG1hY2RfZGYgJT4lIHNlbGVjdChYNC54KSAlPiUgdG9fbSgzMikNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KbWFjZF9tXzIgPC0gdHJhbnNmb3JtKG1hY2RfbSwgTV9UID0gMjApIA0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQojIENob29zZSB0aGUgYXNzZXQgY29ycmVzcG9uZGluZyB0byB0aGlzIHBlcmlvZCAvZmluZCBieSByZXBsYWNpbmcgJ3knIGFyZ3VtZW50Lw0KZ2dwbG90KHByaWNlcywgYWVzKFgxLCBYMTIpKStnZW9tX2xpbmUoKQ0KDQojIEV4dHJhY3QgYXBwcm94aW1hdGUgZGF0ZSBhbmQgY2hvb3NlIG9ubHkgcmVsZXZhbnQgY29sdW1ucw0KcHJpY2VfZGYgPC0gcHJpY2VzICU+JSBmaWx0ZXIoWDEgPiAiMjAxNy0wOS0yMCIsIFgxIDwgIjIwMTctMTAtMjAiKSAlPiUgc2VsZWN0KFgxLCBYMTIpDQoNCiMgVmlzdWFsaXplIGl0IHRvIGNvbmZpcm0gDQpnZ3Bsb3QocHJpY2VfZGYsIGFlcyhYMSwgWDEyKSkrZ2VvbV9saW5lKCkNCg0KIyBFeHRyYWN0IGNvcnJlc3BvbmRpbmcgcGllY2Ugb2YgbWFjZCBkYXRhZnJhbWU6DQptYWNkX2RmIDwtIG1hY2QgJT4lIHNlbGVjdChYMSwgWDEyKSAlPiUgaW5uZXJfam9pbihwcmljZV9kZiwgYnkgPSBjKCJYMSIgPSAiWDEiKSkNCg0KIyBWaXN1YWxpemUgYm90aCB0aGluZ3MgdG9nZXRoZXINCmdncGxvdChtYWNkX2RmLCBhZXMoWDEsIFgxMi55LCBjb2wgPSBYMTIueCkpK2dlb21fbGluZSgpDQoNCiMgdHJhbnNmb3JtIHRvIG1hdHJpeCwgbnVtYmVyIG9mIGNvbHVtbnMgd2lsbCBjb3JyZXNwb25kIHRvIG1vZGVsIHNlbnNpdGl2aXR5IGUuZy4gMTAwIGNvbHVtbnMgfiAyNCBIb3Vycw0KbWFjZF9tIDwtIG1hY2RfZGYgJT4lIHNlbGVjdChYMTIueCkgJT4lIHRvX20oMzIpDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCm1hY2RfbV8zIDwtIHRyYW5zZm9ybShtYWNkX20sIE1fVCA9IDMwKQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQojIENob29zZSB0aGUgYXNzZXQgY29ycmVzcG9uZGluZyB0byB0aGlzIHBlcmlvZCAvZmluZCBieSByZXBsYWNpbmcgJ3knIGFyZ3VtZW50Lw0KZ2dwbG90KHByaWNlcywgYWVzKFgxLCBYNikpK2dlb21fbGluZSgpDQoNCiMgRXh0cmFjdCBhcHByb3hpbWF0ZSBkYXRlIGFuZCBjaG9vc2Ugb25seSByZWxldmFudCBjb2x1bW5zDQpwcmljZV9kZiA8LSBwcmljZXMgJT4lIGZpbHRlcihYMSA+ICIyMDE3LTEwLTE4IiwgWDEgPCAiMjAxNy0xMC0zMCIpICU+JSBzZWxlY3QoWDEsIFg2KQ0KDQojIFZpc3VhbGl6ZSBpdCB0byBjb25maXJtIA0KZ2dwbG90KHByaWNlX2RmLCBhZXMoWDEsIFg2KSkrZ2VvbV9saW5lKCkNCg0KIyBFeHRyYWN0IGNvcnJlc3BvbmRpbmcgcGllY2Ugb2YgbWFjZCBkYXRhZnJhbWU6DQptYWNkX2RmIDwtIG1hY2QgJT4lIHNlbGVjdChYMSwgWDYpICU+JSBpbm5lcl9qb2luKHByaWNlX2RmLCBieSA9IGMoIlgxIiA9ICJYMSIpKQ0KDQojIFZpc3VhbGl6ZSBib3RoIHRoaW5ncyB0b2dldGhlcg0KZ2dwbG90KG1hY2RfZGYsIGFlcyhYMSwgWDYueSwgY29sID0gWDYueCkpK2dlb21fbGluZSgpDQoNCiMgdHJhbnNmb3JtIHRvIG1hdHJpeCwgbnVtYmVyIG9mIGNvbHVtbnMgd2lsbCBjb3JyZXNwb25kIHRvIG1vZGVsIHNlbnNpdGl2aXR5IGUuZy4gMTAwIGNvbHVtbnMgfiAyNCBIb3Vycw0KbWFjZF9tIDwtIG1hY2RfZGYgJT4lIHNlbGVjdChYNi54KSAlPiUgdG9fbSgzMikNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KbWFjZF9tXzQgPC0gdHJhbnNmb3JtKG1hY2RfbSwgTV9UID0gNDApDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQoNCiMgQ2hvb3NlIHRoZSBhc3NldCBjb3JyZXNwb25kaW5nIHRvIHRoaXMgcGVyaW9kIC9maW5kIGJ5IHJlcGxhY2luZyAneScgYXJndW1lbnQvDQpnZ3Bsb3QocHJpY2VzLCBhZXMoWDEsIFgxMSkpK2dlb21fbGluZSgpDQoNCiMgRXh0cmFjdCBhcHByb3hpbWF0ZSBkYXRlIGFuZCBjaG9vc2Ugb25seSByZWxldmFudCBjb2x1bW5zDQpwcmljZV9kZiA8LSBwcmljZXMgJT4lIGZpbHRlcihYMSA+ICIyMDE3LTA5LTIwIiwgWDEgPCAiMjAxNy0xMC0yNCIpICU+JSBzZWxlY3QoWDEsIFgxMSkNCg0KIyBWaXN1YWxpemUgaXQgdG8gY29uZmlybSANCmdncGxvdChwcmljZV9kZiwgYWVzKFgxLCBYMTEpKStnZW9tX2xpbmUoKQ0KDQojIEV4dHJhY3QgY29ycmVzcG9uZGluZyBwaWVjZSBvZiBtYWNkIGRhdGFmcmFtZToNCm1hY2RfZGYgPC0gbWFjZCAlPiUgc2VsZWN0KFgxLCBYMTEpICU+JSBpbm5lcl9qb2luKHByaWNlX2RmLCBieSA9IGMoIlgxIiA9ICJYMSIpKQ0KDQojIFZpc3VhbGl6ZSBib3RoIHRoaW5ncyB0b2dldGhlcg0KZ2dwbG90KG1hY2RfZGYsIGFlcyhYMSwgWDExLnksIGNvbCA9IFgxMS54KSkrZ2VvbV9saW5lKCkNCg0KIyB0cmFuc2Zvcm0gdG8gbWF0cml4LCBudW1iZXIgb2YgY29sdW1ucyB3aWxsIGNvcnJlc3BvbmQgdG8gbW9kZWwgc2Vuc2l0aXZpdHkgZS5nLiAxMDAgY29sdW1ucyB+IDI0IEhvdXJzDQptYWNkX20gPC0gbWFjZF9kZiAlPiUgc2VsZWN0KFgxMS54KSAlPiUgdG9fbSgzMikNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KbWFjZF9tXzUgPC0gdHJhbnNmb3JtKG1hY2RfbSwgTV9UID0gNTApIA0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBDaG9vc2UgdGhlIGFzc2V0IGNvcnJlc3BvbmRpbmcgdG8gdGhpcyBwZXJpb2QgL2ZpbmQgYnkgcmVwbGFjaW5nICd5JyBhcmd1bWVudC8NCmdncGxvdChwcmljZXMsIGFlcyhYMSwgWDEzKSkrZ2VvbV9saW5lKCkNCg0KIyBFeHRyYWN0IGFwcHJveGltYXRlIGRhdGUgYW5kIGNob29zZSBvbmx5IHJlbGV2YW50IGNvbHVtbnMNCnByaWNlX2RmIDwtIHByaWNlcyAlPiUgZmlsdGVyKFgxID4gIjIwMTctMTAtMTAiLCBYMSA8ICIyMDE3LTExLTIwIikgJT4lIHNlbGVjdChYMSwgWDEzKQ0KDQojIFZpc3VhbGl6ZSBpdCB0byBjb25maXJtIA0KZ2dwbG90KHByaWNlX2RmLCBhZXMoWDEsIFgxMykpK2dlb21fbGluZSgpDQoNCiMgRXh0cmFjdCBjb3JyZXNwb25kaW5nIHBpZWNlIG9mIG1hY2QgZGF0YWZyYW1lOg0KbWFjZF9kZiA8LSBtYWNkICU+JSBzZWxlY3QoWDEsIFgxMykgJT4lIGlubmVyX2pvaW4ocHJpY2VfZGYsIGJ5ID0gYygiWDEiID0gIlgxIikpDQoNCiMgVmlzdWFsaXplIGJvdGggdGhpbmdzIHRvZ2V0aGVyDQpnZ3Bsb3QobWFjZF9kZiwgYWVzKFgxLCBYMTMueSwgY29sID0gWDEzLngpKStnZW9tX2xpbmUoKQ0KDQojIHRyYW5zZm9ybSB0byBtYXRyaXgsIG51bWJlciBvZiBjb2x1bW5zIHdpbGwgY29ycmVzcG9uZCB0byBtb2RlbCBzZW5zaXRpdml0eSBlLmcuIDEwMCBjb2x1bW5zIH4gMjQgSG91cnMNCm1hY2RfbSA8LSBtYWNkX2RmICU+JSBzZWxlY3QoWDEzLngpICU+JSB0b19tKDMyKQ0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQptYWNkX21fNiA8LSB0cmFuc2Zvcm0obWFjZF9tLCBNX1QgPSA2MCkNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KIyBDb21iaW5lIGFsbCBvZiB0aGF0IDopDQptYWNkX01MMSA8LSByYmluZChtYWNkX21fMSxtYWNkX21fMixtYWNkX21fMyxtYWNkX21fNCxtYWNkX21fNSxtYWNkX21fNikNCg0KYGBgDQoNCk5vdyB3ZSBoYXZlIG91ciBsYWJlbGxlZCBkYXRhc2V0DQoNCmBgYHtyfQ0KIyMgVmlzdWFsaXplIG5ldyBtYXRyaXggaW4gM0QNCnBsb3RfbHkoeiA9IGFzLm1hdHJpeChtYWNkX01MMVssMTozMl0pLCB0eXBlID0gInN1cmZhY2UiKQ0KYGBgDQoNCiMjIFJlZ3Jlc3Npb24gbW9kZWwNCg0KTmV4dCB3ZSBjYW4gZml0IHRoZSBtb2RlbCBqdXN0IGJ5IHNwZWNpZnlpbmcgd2hhdCBhcmUgdGhlICdMYWJlbCcgY29sdW1uLiBJbiB0aGlzIGNhc2Ugb3VyIGxhYmVsIGlzIGEgbnVtZXJpYy4NCg0KTW9kZWwgd2Ugd2lsbCBmaXQgaW4gdGhpcyBjYXNlIHdpbGwgaGF2ZSBjb25maWd1cmF0aW9uOg0KDQpJbnB1dHMgIHwgaGlkZGVuIGxheWVyMSB8IGhpZGRlbiBsYXllcjIgfCBPdXRwdXQNCi0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tIHwgLS0tLS0tLS0tLS0tLSB8IC0tLS0tLS0tLS0tLS0NCjMyICAgICAgfCAgICAgICAxMDAgICAgIHwgICAgICAxMDAgICAgICB8ICAgIDENCg0KYGBge3J9DQojIyMjIEZpdHRpbmcgRGVlcCBMZWFybmluZyBOZXQgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyMgRml0IG1vZGVsIG5vdzoNCiMgc3RhcnQgaDJvIHZpcnR1YWwgbWFjaGluZQ0KaDJvLmluaXQoKQ0KIyBsb2FkIGRhdGEgaW50byBoMm8gZW52aXJvbm1lbnQNCm1hY2RfTUwgIDwtIGFzLmgybyh4ID0gbWFjZF9NTDEsIGRlc3RpbmF0aW9uX2ZyYW1lID0gIm1hY2RfTUwiKQ0KDQojIGZpdCBtb2RlbHMgZnJvbSBzaW1wbGVzdCB0byBtb3JlIGNvbXBsZXgNCk1vZGVsQSA8LSBoMm8uZGVlcGxlYXJuaW5nKA0KICB4ID0gbmFtZXMobWFjZF9NTFssMTozMl0pLCANCiAgeSA9ICJNX1QiLA0KICB0cmFpbmluZ19mcmFtZSA9IG1hY2RfTUwsDQogIGFjdGl2YXRpb24gPSAiVGFuaCIsDQogIG92ZXJ3cml0ZV93aXRoX2Jlc3RfbW9kZWwgPSBUUlVFLCANCiAgYXV0b2VuY29kZXIgPSBGQUxTRSwgDQogIGhpZGRlbiA9IGMoMTAwLDEwMCksIA0KICBsb3NzID0gIkF1dG9tYXRpYyIsDQogIHNwYXJzZSA9IFRSVUUsDQogIGwxID0gMWUtNCwNCiAgZGlzdHJpYnV0aW9uID0gIkFVVE8iLA0KICBzdG9wcGluZ19tZXRyaWMgPSAiTVNFIiwNCiAgI2JhbGFuY2VfY2xhc3NlcyA9IFQsDQogIGVwb2NocyA9IDYwMCkNCmBgYA0KDQpJdCB0YWtlcyBhIHdoaWxlIHVudGlsIGl0IGlzIHRyYWluZWQ6DQoNCmBgYHtyfQ0KTW9kZWxBDQpzdW1tYXJ5KE1vZGVsQSkNCmgyby5wZXJmb3JtYW5jZShNb2RlbEEpDQpgYGANCg0KDQoNCmBgYHtyfQ0KIyB0byByZXR1cm4gcHJlZGljdGVkIGNsYXNzZXMNCnByZWRpY3RlZCA8LSBoMm8ucHJlZGljdChNb2RlbEEsIG1hY2RfTUwpICU+JSBhcy5kYXRhLmZyYW1lKCkNCmBgYA0KDQpOb3RpY2UgdGhhdCBtb2RlbCBpcyBtYWtpbmcgbWlzdGFrZXMgc29tZXRpbWVzIGV2ZW4gcmV0dXJuaW5nIG5lZ2F0aXZlIHZhbHVlcyEgDQoNCkluIGZhY3Qgd2Ugc2hvdWxkIHRyeSBkaWZmZXJlbnQgbW9kZWxzIHVudGlsIHJlc3VsdHMgYXJlIGJldHRlciB3aGlsZSBjaG9vc2luZyBsZXNzIHBvc3NpYmxlIGNvbXBsZXhpdHkgbW9kZWwsIGZvciBleGFtcGxlOg0KDQoNCmBgYHtyfQ0KIyBmaXQgbW9kZWxzIGZyb20gc2ltcGxlc3QgdG8gbW9yZSBjb21wbGV4DQpNb2RlbEIgPC0gaDJvLmRlZXBsZWFybmluZygNCiAgeCA9IG5hbWVzKG1hY2RfTUxbLDE6MzJdKSwgDQogIHkgPSAiTV9UIiwNCiAgdHJhaW5pbmdfZnJhbWUgPSBtYWNkX01MLA0KICBhY3RpdmF0aW9uID0gIlRhbmgiLA0KICBvdmVyd3JpdGVfd2l0aF9iZXN0X21vZGVsID0gVFJVRSwgDQogIGF1dG9lbmNvZGVyID0gRkFMU0UsIA0KICBoaWRkZW4gPSBjKDMwLDIwLDMwKSwgDQogIGxvc3MgPSAiQXV0b21hdGljIiwNCiAgc3BhcnNlID0gVFJVRSwNCiAgbDEgPSAxZS00LA0KICBkaXN0cmlidXRpb24gPSAiQVVUTyIsDQogIHN0b3BwaW5nX21ldHJpYyA9ICJNU0UiLA0KICAjYmFsYW5jZV9jbGFzc2VzID0gVCwNCiAgZXBvY2hzID0gNjAwKQ0KYGBgDQoNCg0KYGBge3J9DQpoMm8ucGVyZm9ybWFuY2UoTW9kZWxCKQ0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KIyBmaXQgbW9kZWxzIGZyb20gc2ltcGxlc3QgdG8gbW9yZSBjb21wbGV4DQpNb2RlbEMgPC0gaDJvLmRlZXBsZWFybmluZygNCiAgeCA9IG5hbWVzKG1hY2RfTUxbLDE6MzJdKSwgDQogIHkgPSAiTV9UIiwNCiAgdHJhaW5pbmdfZnJhbWUgPSBtYWNkX01MLA0KICBhY3RpdmF0aW9uID0gIlRhbmgiLA0KICBvdmVyd3JpdGVfd2l0aF9iZXN0X21vZGVsID0gVFJVRSwgDQogIGF1dG9lbmNvZGVyID0gRkFMU0UsIA0KICBoaWRkZW4gPSBjKDMwLDMwKSwgDQogIGxvc3MgPSAiQXV0b21hdGljIiwNCiAgc3BhcnNlID0gVFJVRSwNCiAgbDEgPSAxZS00LA0KICBkaXN0cmlidXRpb24gPSAiQVVUTyIsDQogIHN0b3BwaW5nX21ldHJpYyA9ICJNU0UiLA0KICAjYmFsYW5jZV9jbGFzc2VzID0gVCwNCiAgZXBvY2hzID0gNjAwKQ0KYGBgDQoNCg0KYGBge3J9DQpoMm8ucGVyZm9ybWFuY2UoTW9kZWxDKQ0KYGBgDQoNCg0KYGBge3J9DQojIGZpdCBtb2RlbHMgZnJvbSBzaW1wbGVzdCB0byBtb3JlIGNvbXBsZXgNCk1vZGVsRCA8LSBoMm8uZGVlcGxlYXJuaW5nKA0KICB4ID0gbmFtZXMobWFjZF9NTFssMTozMl0pLCANCiAgeSA9ICJNX1QiLA0KICB0cmFpbmluZ19mcmFtZSA9IG1hY2RfTUwsDQogIGFjdGl2YXRpb24gPSAiVGFuaCIsDQogIG92ZXJ3cml0ZV93aXRoX2Jlc3RfbW9kZWwgPSBUUlVFLCANCiAgYXV0b2VuY29kZXIgPSBGQUxTRSwgDQogIGhpZGRlbiA9IGMoMjAwLDEwMCwyMDApLCANCiAgbG9zcyA9ICJBdXRvbWF0aWMiLA0KICBzcGFyc2UgPSBUUlVFLA0KICBsMSA9IDFlLTQsDQogIGRpc3RyaWJ1dGlvbiA9ICJBVVRPIiwNCiAgc3RvcHBpbmdfbWV0cmljID0gIk1TRSIsDQogICNiYWxhbmNlX2NsYXNzZXMgPSBULA0KICBlcG9jaHMgPSA2MDApDQpgYGANCg0KDQpgYGB7cn0NCmgyby5wZXJmb3JtYW5jZShNb2RlbEQpDQpgYGANCg0KV2UgY2FuIGFsc28gdHJ5IG90aGVyIHBhcmFtZXRlcnMgaW4gTW9kZWwgQSBmb3IgZXhhbXBsZSBjb21wdXRpbmcgdmFyaWFibGVzIGltcG9ydGFuY2VzIChub3QgcmVsZXZhbnQgZm9yIHRoaXMgdGFzaykNCg0KYGBge3J9DQojIGZpdCBtb2RlbHMgZnJvbSBzaW1wbGVzdCB0byBtb3JlIGNvbXBsZXgNCk1vZGVsQSA8LSBoMm8uZGVlcGxlYXJuaW5nKA0KICB4ID0gbmFtZXMobWFjZF9NTFssMTozMl0pLCANCiAgeSA9ICJNX1QiLA0KICB0cmFpbmluZ19mcmFtZSA9IG1hY2RfTUwsDQogIGFjdGl2YXRpb24gPSAiVGFuaCIsDQogIG92ZXJ3cml0ZV93aXRoX2Jlc3RfbW9kZWwgPSBUUlVFLCANCiAgYXV0b2VuY29kZXIgPSBGQUxTRSwgDQogIGhpZGRlbiA9IGMoMTAwLDEwMCksIA0KICBsb3NzID0gIkF1dG9tYXRpYyIsDQogIHNwYXJzZSA9IFRSVUUsDQogIGwxID0gMWUtNCwNCiAgZGlzdHJpYnV0aW9uID0gIkFVVE8iLA0KICBzdG9wcGluZ19tZXRyaWMgPSAiTVNFIiwNCiAgI2JhbGFuY2VfY2xhc3NlcyA9IFQsDQogIHZhcmlhYmxlX2ltcG9ydGFuY2VzID0gVCwNCiAgZXBvY2hzID0gNjAwKQ0KYGBgDQoNCg0KYGBge3J9DQojIGNvbXB1dGluZyB2YXJpYWJsZSBpbXBvcnRhbmNlcw0KaDJvLnZhcmltcChNb2RlbEEpICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIGhlYWQoKQ0KYGBgDQpgYGB7cn0NCg0KIyBjb21wdXRpbmcgdmFyaWFibGUgaW1wb3J0YW5jZXMNCmgyby52YXJpbXAoTW9kZWxBKSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSB0YWlsKCkNCg0KYGBgDQoNCmBgYHtyfQ0KIyBwbG90dGluZyB0aGF0DQpteV92YXJpYWJsZXMgPC0gaDJvLnZhcmltcChNb2RlbEEpICU+JSBhcy5kYXRhLmZyYW1lKCkgDQoNCm15X3ZhcmlhYmxlcyRwZXJjZW50YWdlICU+JSBwbG90KCkNCmBgYA0KDQojIyMgc2VhcmNoaW5nIGh5cGVycGFyYW1ldGVycw0KDQpgYGB7cn0NCmh5cGVyX3BhcmFtcyA8LSBsaXN0KA0KICBhY3RpdmF0aW9uPWMoIlJlY3RpZmllciIsIlRhbmgiLCJNYXhvdXQiLCJSZWN0aWZpZXJXaXRoRHJvcG91dCIsIlRhbmhXaXRoRHJvcG91dCIsIk1heG91dFdpdGhEcm9wb3V0IiksDQogIGhpZGRlbj1saXN0KGMoMTAwLDEwMCksYyg1MCw1MCksYygzMCwzMCwzMCksYygyNSwyNSwyNSwyNSkpLA0KICBpbnB1dF9kcm9wb3V0X3JhdGlvPWMoMCwwLjA1KSwNCiAgbDE9c2VxKDAsMWUtNCwxZS02KSwNCiAgbDI9c2VxKDAsMWUtNCwxZS02KQ0KKQ0KYGBgDQoNClRoaXMgaXMgdGhlIG1ldGhvZCBvZiBmaW5kaW5nIHRoZSBiZXN0IG1vZGVsIHJ1bm5pbmcgaXQgYXQgb25jZToNCnNlZSBodHRwczovL2dpdGh1Yi5jb20vaDJvYWkvaDJvLXR1dG9yaWFscy90cmVlL21hc3Rlci90dXRvcmlhbHMvZGVlcGxlYXJuaW5nDQoNCmBgYHtyfQ0KIyMgU3RvcCBvbmNlIHRoZSB0b3AgNSBtb2RlbHMgYXJlIHdpdGhpbiAxJSBvZiBlYWNoIG90aGVyIChpLmUuLCB0aGUgd2luZG93ZWQgYXZlcmFnZSB2YXJpZXMgbGVzcyB0aGFuIDElKQ0Kc2VhcmNoX2NyaXRlcmlhID0gbGlzdChzdHJhdGVneSA9ICJSYW5kb21EaXNjcmV0ZSIsIG1heF9ydW50aW1lX3NlY3MgPSAzNjAsIG1heF9tb2RlbHMgPSAxMDAsIHNlZWQ9MTIzNDU2Nywgc3RvcHBpbmdfcm91bmRzPTUsIHN0b3BwaW5nX3RvbGVyYW5jZT0xZS0yKQ0KZGxfcmFuZG9tX2dyaWQgPC0gaDJvLmdyaWQoDQogIGFsZ29yaXRobT0iZGVlcGxlYXJuaW5nIiwNCiAgI2dyaWRfaWQgPSAiZGxfZ3JpZF9yYW5kb20iLA0KICB0cmFpbmluZ19mcmFtZT1tYWNkX01MLA0KICB4PW5hbWVzKG1hY2RfTUxbLDE6MzJdKSwgDQogIHk9Ik1fVCIsDQogIGVwb2Nocz0xLA0KICBzdG9wcGluZ19tZXRyaWM9Ik1TRSIsDQogIHN0b3BwaW5nX3RvbGVyYW5jZT0xZS0yLCAgICAgICAgIyMgc3RvcCB3aGVuIGxvZ2xvc3MgZG9lcyBub3QgaW1wcm92ZSBieSA+PTElIGZvciAyIHNjb3JpbmcgZXZlbnRzDQogIHN0b3BwaW5nX3JvdW5kcz0yLA0KICBzY29yZV92YWxpZGF0aW9uX3NhbXBsZXM9MTAwMDAsICMjIGRvd25zYW1wbGUgdmFsaWRhdGlvbiBzZXQgZm9yIGZhc3RlciBzY29yaW5nDQogIHNjb3JlX2R1dHlfY3ljbGU9MC4wMjUsICAgICAgICAgIyMgZG9uJ3Qgc2NvcmUgbW9yZSB0aGFuIDIuNSUgb2YgdGhlIHdhbGwgdGltZQ0KICBtYXhfdzI9MTAsICAgICAgICAgICAgICAgICAgICAgICMjIGNhbiBoZWxwIGltcHJvdmUgc3RhYmlsaXR5IGZvciBSZWN0aWZpZXINCiAgaHlwZXJfcGFyYW1zID0gaHlwZXJfcGFyYW1zLA0KICBzZWFyY2hfY3JpdGVyaWEgPSBzZWFyY2hfY3JpdGVyaWENCikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KZ3JpZCA8LSBoMm8uZ2V0R3JpZCgiZGxfZ3JpZF9yYW5kb20iLHNvcnRfYnk9Ik1TRSIsZGVjcmVhc2luZz1GQUxTRSkNCmdyaWQNCmBgYA0KDQouLi4gbmVlZCB0aW1lIHRvIHN0dWR5IHRoaXMgcmVzdWx0LCBpc24ndCBpdD8/Pw0KDQojIyBMZXQncyB0cnkgdG8gcHJlZGljdD8NCg0KTGV0J3MgYXNzdW1lIHdlIGhhdmUgdGhlIGxhdGVzdCBpbmZvcm1hdGlvbi4uLiB3aGF0IHdpbGwgdGhlIG1vZGVsIHdpbGwgc2F5Pw0KDQpgYGB7cn0NCm1hY2RfbGF0ZXN0IDwtIG1hY2RfTUwxWzIwMCwgMTozMl0gI2xhYmVsID0gNTANCm1hY2RfbGFiZWwgIDwtIG1hY2RfTUwxWzIwMCwgMzNdICNsYWJlbCA9IDUwDQpgYGANCg0KYGBge3J9DQojIGxvYWQgZGF0YSBpbnRvIGgybyBlbnZpcm9ubWVudA0KbWFjZF8yMDAgIDwtIGFzLmgybyh4ID0gbWFjZF9sYXRlc3QsIGRlc3RpbmF0aW9uX2ZyYW1lID0gIm1hY2RfMjAwIikNCg0KcHJlZDIwMCA8LSBoMm8ucHJlZGljdChNb2RlbEEsIG1hY2RfMjAwKSAlPiUgYXMuZGF0YS5mcmFtZSgpDQoNCnByZWQyMDANCmBgYA0KDQoNCg0KIyMgV2hhdCBhYm91dCBDbGFzc2lmaWNhdGlvbiBNb2RlbD8NCg0KSW4gY2FzZSBvdXIgbW9kZWwgd2lsbCBoYXZlIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgYXMgYSBsYWJlbCB3ZSBjYW4gYXR0ZW1wdCB0byBnbyBmb3IgY2xhc3NpZmljYXRpb24gbW9kZWxsaW5nDQoNCkkgd291bGQgdGhlbiByZS1jcmVhdGUgZGF0YXNldCBieSB0cmFuc2Zvcm1pbmcgdG8gY2F0ZWdvcmljYWwgdmFyaWFibGVzDQoNCmBgYHtyfQ0KIyMjIyBNYW51YWxseSBTZWxlY3RpbmcgZGF0YS4uLiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIE1hcmtldCBQZXJpb2RzDQojIDEuIEJ1bGwgbm9ybWFsDQojIDIuIEJ1bGwgdm9sYXRpbGUNCiMgMy4gQmVhciBub3JtYWwNCiMgNC4gQmVhciB2b2xhdGlsZQ0KIyA1LiBTaWRld2F5cyBxdWlldA0KIyA2LiBTaWRld2F5cyB2b2xhdGlsZQ0KDQoNCiMgRXh0cmFjdCBhcHByb3hpbWF0ZSBkYXRlIGFuZCBjaG9vc2Ugb25seSByZWxldmFudCBjb2x1bW5zDQpwcmljZV9kZiA8LSBwcmljZXMgJT4lIGZpbHRlcihYMSA+ICIyMDE3LTExLTA1IiwgWDEgPCAiMjAxNy0xMS0yNSIpICU+JSBzZWxlY3QoWDEsIFgzKQ0KDQojIEV4dHJhY3QgY29ycmVzcG9uZGluZyBwaWVjZSBvZiBtYWNkIGRhdGFmcmFtZToNCm1hY2RfZGYgPC0gbWFjZCAlPiUgc2VsZWN0KFgxLCBYMykgJT4lIGlubmVyX2pvaW4ocHJpY2VfZGYsIGJ5ID0gYygiWDEiID0gIlgxIikpDQoNCiMgdHJhbnNmb3JtIHRvIG1hdHJpeCwgbnVtYmVyIG9mIGNvbHVtbnMgd2lsbCBjb3JyZXNwb25kIHRvIG1vZGVsIHNlbnNpdGl2aXR5IGUuZy4gMTAwIGNvbHVtbnMgfiAyNCBIb3Vycw0KbWFjZF9tIDwtIG1hY2RfZGYgJT4lIHNlbGVjdChYMy54KSAlPiUgdG9fbSgzMikNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQojIGFkZCBuZXcgY29sdW1uIHRvIHRoaXMgbWF0cml4IHdpdGggdmFsdWUgMQ0KbWFjZF9tXzEgPC0gdHJhbnNmb3JtKG1hY2RfbSwgTV9UID0gIm9uZSIpDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQoNCiMgRXh0cmFjdCBhcHByb3hpbWF0ZSBkYXRlIGFuZCBjaG9vc2Ugb25seSByZWxldmFudCBjb2x1bW5zDQpwcmljZV9kZiA8LSBwcmljZXMgJT4lIGZpbHRlcihYMSA+ICIyMDE3LTEwLTAyIiwgWDEgPCAiMjAxNy0xMC0wNyIpICU+JSBzZWxlY3QoWDEsIFg0KQ0KDQojIEV4dHJhY3QgY29ycmVzcG9uZGluZyBwaWVjZSBvZiBtYWNkIGRhdGFmcmFtZToNCm1hY2RfZGYgPC0gbWFjZCAlPiUgc2VsZWN0KFgxLCBYNCkgJT4lIGlubmVyX2pvaW4ocHJpY2VfZGYsIGJ5ID0gYygiWDEiID0gIlgxIikpDQoNCiMgdHJhbnNmb3JtIHRvIG1hdHJpeCwgbnVtYmVyIG9mIGNvbHVtbnMgd2lsbCBjb3JyZXNwb25kIHRvIG1vZGVsIHNlbnNpdGl2aXR5IGUuZy4gMTAwIGNvbHVtbnMgfiAyNCBIb3Vycw0KbWFjZF9tIDwtIG1hY2RfZGYgJT4lIHNlbGVjdChYNC54KSAlPiUgdG9fbSgzMikNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KbWFjZF9tXzIgPC0gdHJhbnNmb3JtKG1hY2RfbSwgTV9UID0gInR3byIpIA0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQojIEV4dHJhY3QgYXBwcm94aW1hdGUgZGF0ZSBhbmQgY2hvb3NlIG9ubHkgcmVsZXZhbnQgY29sdW1ucw0KcHJpY2VfZGYgPC0gcHJpY2VzICU+JSBmaWx0ZXIoWDEgPiAiMjAxNy0wOS0yMCIsIFgxIDwgIjIwMTctMTAtMjAiKSAlPiUgc2VsZWN0KFgxLCBYMTIpDQoNCiMgRXh0cmFjdCBjb3JyZXNwb25kaW5nIHBpZWNlIG9mIG1hY2QgZGF0YWZyYW1lOg0KbWFjZF9kZiA8LSBtYWNkICU+JSBzZWxlY3QoWDEsIFgxMikgJT4lIGlubmVyX2pvaW4ocHJpY2VfZGYsIGJ5ID0gYygiWDEiID0gIlgxIikpDQoNCiMgdHJhbnNmb3JtIHRvIG1hdHJpeCwgbnVtYmVyIG9mIGNvbHVtbnMgd2lsbCBjb3JyZXNwb25kIHRvIG1vZGVsIHNlbnNpdGl2aXR5IGUuZy4gMTAwIGNvbHVtbnMgfiAyNCBIb3Vycw0KbWFjZF9tIDwtIG1hY2RfZGYgJT4lIHNlbGVjdChYMTIueCkgJT4lIHRvX20oMzIpDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCm1hY2RfbV8zIDwtIHRyYW5zZm9ybShtYWNkX20sIE1fVCA9ICJ0cmVlIikNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KIyBFeHRyYWN0IGFwcHJveGltYXRlIGRhdGUgYW5kIGNob29zZSBvbmx5IHJlbGV2YW50IGNvbHVtbnMNCnByaWNlX2RmIDwtIHByaWNlcyAlPiUgZmlsdGVyKFgxID4gIjIwMTctMTAtMTgiLCBYMSA8ICIyMDE3LTEwLTMwIikgJT4lIHNlbGVjdChYMSwgWDYpDQoNCiMgRXh0cmFjdCBjb3JyZXNwb25kaW5nIHBpZWNlIG9mIG1hY2QgZGF0YWZyYW1lOg0KbWFjZF9kZiA8LSBtYWNkICU+JSBzZWxlY3QoWDEsIFg2KSAlPiUgaW5uZXJfam9pbihwcmljZV9kZiwgYnkgPSBjKCJYMSIgPSAiWDEiKSkNCg0KIyB0cmFuc2Zvcm0gdG8gbWF0cml4LCBudW1iZXIgb2YgY29sdW1ucyB3aWxsIGNvcnJlc3BvbmQgdG8gbW9kZWwgc2Vuc2l0aXZpdHkgZS5nLiAxMDAgY29sdW1ucyB+IDI0IEhvdXJzDQptYWNkX20gPC0gbWFjZF9kZiAlPiUgc2VsZWN0KFg2LngpICU+JSB0b19tKDMyKQ0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQptYWNkX21fNCA8LSB0cmFuc2Zvcm0obWFjZF9tLCBNX1QgPSAiZm91ciIpDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQoNCiMgRXh0cmFjdCBhcHByb3hpbWF0ZSBkYXRlIGFuZCBjaG9vc2Ugb25seSByZWxldmFudCBjb2x1bW5zDQpwcmljZV9kZiA8LSBwcmljZXMgJT4lIGZpbHRlcihYMSA+ICIyMDE3LTA5LTIwIiwgWDEgPCAiMjAxNy0xMC0yNCIpICU+JSBzZWxlY3QoWDEsIFgxMSkNCg0KIyBFeHRyYWN0IGNvcnJlc3BvbmRpbmcgcGllY2Ugb2YgbWFjZCBkYXRhZnJhbWU6DQptYWNkX2RmIDwtIG1hY2QgJT4lIHNlbGVjdChYMSwgWDExKSAlPiUgaW5uZXJfam9pbihwcmljZV9kZiwgYnkgPSBjKCJYMSIgPSAiWDEiKSkNCg0KIyB0cmFuc2Zvcm0gdG8gbWF0cml4LCBudW1iZXIgb2YgY29sdW1ucyB3aWxsIGNvcnJlc3BvbmQgdG8gbW9kZWwgc2Vuc2l0aXZpdHkgZS5nLiAxMDAgY29sdW1ucyB+IDI0IEhvdXJzDQptYWNkX20gPC0gbWFjZF9kZiAlPiUgc2VsZWN0KFgxMS54KSAlPiUgdG9fbSgzMikNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KbWFjZF9tXzUgPC0gdHJhbnNmb3JtKG1hY2RfbSwgTV9UID0gImZpdmUiKSANCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KIyBFeHRyYWN0IGFwcHJveGltYXRlIGRhdGUgYW5kIGNob29zZSBvbmx5IHJlbGV2YW50IGNvbHVtbnMNCnByaWNlX2RmIDwtIHByaWNlcyAlPiUgZmlsdGVyKFgxID4gIjIwMTctMTAtMTAiLCBYMSA8ICIyMDE3LTExLTIwIikgJT4lIHNlbGVjdChYMSwgWDEzKQ0KDQojIEV4dHJhY3QgY29ycmVzcG9uZGluZyBwaWVjZSBvZiBtYWNkIGRhdGFmcmFtZToNCm1hY2RfZGYgPC0gbWFjZCAlPiUgc2VsZWN0KFgxLCBYMTMpICU+JSBpbm5lcl9qb2luKHByaWNlX2RmLCBieSA9IGMoIlgxIiA9ICJYMSIpKQ0KDQojIHRyYW5zZm9ybSB0byBtYXRyaXgsIG51bWJlciBvZiBjb2x1bW5zIHdpbGwgY29ycmVzcG9uZCB0byBtb2RlbCBzZW5zaXRpdml0eSBlLmcuIDEwMCBjb2x1bW5zIH4gMjQgSG91cnMNCm1hY2RfbSA8LSBtYWNkX2RmICU+JSBzZWxlY3QoWDEzLngpICU+JSB0b19tKDMyKQ0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQptYWNkX21fNiA8LSB0cmFuc2Zvcm0obWFjZF9tLCBNX1QgPSAic2l4IikNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KIyBDb21iaW5lIGFsbCBvZiB0aGF0IDopDQptYWNkX01MMiA8LSByYmluZChtYWNkX21fMSxtYWNkX21fMixtYWNkX21fMyxtYWNkX21fNCxtYWNkX21fNSxtYWNkX21fNikNCmBgYA0KDQoNCg0KYGBge3J9DQojIGZpdCBtb2RlbHMgZnJvbSBzaW1wbGVzdCB0byBtb3JlIGNvbXBsZXgNCmgyby5pbml0KCkNCiMgbG9hZCBkYXRhIGludG8gaDJvIGVudmlyb25tZW50DQptYWNkX0NhdCAgPC0gYXMuaDJvKHggPSBtYWNkX01MMiwgZGVzdGluYXRpb25fZnJhbWUgPSAibWFjZF9DYXQiKQ0KDQpNb2RlbENBIDwtIGgyby5kZWVwbGVhcm5pbmcoDQogIHggPSBuYW1lcyhtYWNkX0NhdFssMTozMl0pLCANCiAgeSA9ICJNX1QiLA0KICB0cmFpbmluZ19mcmFtZSA9IG1hY2RfQ2F0LA0KICBhY3RpdmF0aW9uID0gIlRhbmgiLA0KICBvdmVyd3JpdGVfd2l0aF9iZXN0X21vZGVsID0gVFJVRSwgDQogIGF1dG9lbmNvZGVyID0gRkFMU0UsIA0KICBoaWRkZW4gPSBjKDEwMCwxMDApLCANCiAgbG9zcyA9ICJBdXRvbWF0aWMiLA0KICBzcGFyc2UgPSBUUlVFLA0KICBsMSA9IDFlLTQsDQogIGRpc3RyaWJ1dGlvbiA9ICJBVVRPIiwNCiAgc3RvcHBpbmdfbWV0cmljID0gIkFVVE8iLA0KICAjYmFsYW5jZV9jbGFzc2VzID0gVCwNCiAgI3ZhcmlhYmxlX2ltcG9ydGFuY2VzID0gVCwNCiAgZXBvY2hzID0gNjAwKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShNb2RlbENBKQ0KaDJvLnBlcmZvcm1hbmNlKE1vZGVsQ0EpDQpgYGANCg0KIyMgTGV0J3MgdHJ5IHRvIHByZWRpY3Q/DQoNCkxldCdzIGFzc3VtZSB3ZSBoYXZlIHRoZSBsYXRlc3QgaW5mb3JtYXRpb24uLi4gd2hhdCB3aWxsIHRoZSBtb2RlbCB3aWxsIHNheT8NCg0KYGBge3J9DQptYWNkX2xhdGVzdCA8LSBtYWNkX01MMlsyMDAsIDE6MzJdICNsYWJlbCA9IGZpdmUNCm1hY2RfbGF0ZXN0JE1fVCA8LSAib25lIg0KbWFjZF9sYWJlbCAgPC0gbWFjZF9NTDJbMjAwLCAzM10gI2xhYmVsID0gZml2ZQ0KYGBgDQoNCmBgYHtyfQ0KIyBsb2FkIGRhdGEgaW50byBoMm8gZW52aXJvbm1lbnQNCm1hY2RfMjAwICA8LSBhcy5oMm8oeCA9IG1hY2RfbGF0ZXN0LCBkZXN0aW5hdGlvbl9mcmFtZSA9ICJtYWNkXzIwMCIpDQoNCnByZWQyMDAgPC0gaDJvLnByZWRpY3QoTW9kZWxDQSwgbWFjZF8yMDApICU+JSBhcy5kYXRhLmZyYW1lKCkNCg0KcHJlZDIwMCRwcmVkaWN0DQpgYGANCg0KYGBge3J9DQojIG1vcmUgdHJpYWxzDQpNb2RlbENBMSA8LSBoMm8uZGVlcGxlYXJuaW5nKA0KICB4ID0gbmFtZXMobWFjZF9DYXRbLDE6MzJdKSwgDQogIHkgPSAiTV9UIiwNCiAgdHJhaW5pbmdfZnJhbWUgPSBtYWNkX0NhdCwNCiAgYWN0aXZhdGlvbiA9ICJUYW5oIiwNCiAgb3ZlcndyaXRlX3dpdGhfYmVzdF9tb2RlbCA9IFRSVUUsIA0KICBhdXRvZW5jb2RlciA9IEZBTFNFLCANCiAgaGlkZGVuID0gYygyMDAsMjAwKSwgDQogIGxvc3MgPSAiQXV0b21hdGljIiwNCiAgc3BhcnNlID0gVFJVRSwNCiAgbDEgPSAxZS00LA0KICBkaXN0cmlidXRpb24gPSAiQVVUTyIsDQogIHN0b3BwaW5nX21ldHJpYyA9ICJBVVRPIiwNCiAgI2JhbGFuY2VfY2xhc3NlcyA9IFQsDQogICN2YXJpYWJsZV9pbXBvcnRhbmNlcyA9IFQsDQogIGVwb2NocyA9IDYwMCkNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkoTW9kZWxDQTEpDQpgYGANCg0KVGhlcmUgYXJlIHByZXR0eSBkaWZmZXJlbnQgcmVzdWx0cy4uLiBwb3RlbnRpYWxseSB0aGUgZXJyb3IgcmF0ZSBpcyBoaWdoIQ0KDQpgYGB7cn0NCmgyby5wZXJmb3JtYW5jZShNb2RlbENBMSkNCmBgYA0KDQoNCiMjIFNhdmUgdGhlIG1vZGVsDQoNCkluIGNhc2Ugd2Ugd2FudCB0byBzYXZlIHRoZSBtb2RlbCBwZXJzaXN0ZW50bHkgd2UgY2FuIGRvIHNvDQoNCmBgYHtyfQ0KIyBzYXZlIHRoZSBtb2RlbCwgcGFyYW1ldGVyIGZvcmNlID0gVFJVRSB3aWxsIG92ZXJ3cml0ZSBleGlzdGluZyBmaWxlDQpoMm8uc2F2ZU1vZGVsKFNpbXBsZUEsICJtb2RlbHMvYnVsbF9ub3JtLmJpbiIsIGZvcmNlID0gVFJVRSkNCg0KIyBzaHV0ZG93bi4uLg0KaDJvLnNodXRkb3duKHByb21wdCA9IEYpDQpgYGANCg0KIyMgQ29uY2x1c2lvbg0KDQpUaGlzIHByb2NlZHVyZSBjYW4gYmUgcmVwZWF0ZWQgZm9yIGV2ZXJ5IG1hcmtldCBwZXJpb2QuLi4gYW5kIGhvcGVmdWxseSBpdCB3aWxsIGJyaW5nIHNvbWUgZnJ1aXRzLi4uPw0KDQoNCg0KIyBVdGlsaXR5IENvZGUNCg0KIyMgQWRhcHRpbmcgZnVuY3Rpb24gdG9fbQ0KDQpgYGB7cn0NCg0KIyBGdW5jdGlvbiBjb252ZXJ0aW5nIHRpbWUgc2VyaWVzIGRhdGEgdG8gbWF0cml4DQp0b19tIDwtIGZ1bmN0aW9uKHgsIG5fY29scykgew0KICAjIyMgUFVSUE9TRTogVHJhbnNmb3JtIFRpbWUgU2VyaWVzIENvbHVtbiBvZiB0aGUgZGF0YWZyYW1lIHRvIHRoZSBtYXRyaXgNCiAgIyAgICAgICAgICAgIHdpdGggc3BlY2lmaWVkIG51bWJlciBvZiBjb2x1bW5zLiBOdW1iZXIgb2Ygcm93cyB3aWxsIGJlIGF1dG9tYXRpY2FsbHkNCiAgIyAgICAgICAgICAgIGZvdW5kIGFuZCByZW1haW5pbmcgZGF0YSBwb2ludHMgZGlzY2FyZGVkDQogICMgIyBVbmNvbW1lbnQgdmFyaWFibGUgdG8gZGVidWcgZnVuY3Rpb24NCiAgIyB4IC08IGRhdGFmcmFtZSB3aXRoIG9uZSBjb2x1bW4NCiAgDQogICMgeCA8LSBERl9URU1QDQogICMgbl9jb2xzIDwtIDE1MA0KICANCiAgIyBnZXQgaW50ZXJtZWRpYXRlIG9iamVjdCBhbmQgZGltZW5zaW9uDQogIFN0ZXAxIDwtIHgNCiAgIyBmaW5kIG51bWJlciBvZiByb3dzIG9mIGRhdGEgZnJhbWUNCiAgbnJvd3MgPC0gU3RlcDEgJT4lIG5yb3coKQ0KICAjIGZpbmQgdGhlIG51bWJlciBvZiByb3cgaW4gYSBtYXRyaXggKFdob2xlIFJvd3MpLCB0aGUgdmFsdWUgd2lsbCBoYXZlIGRlY2ltYWxzLi4uDQogIFdOIDwtIG5yb3dzL25fY29scw0KICAjIyBleHRyYWN0IHRoZSB3aG9sZSBudW1iZXIgdW5jb21tZW50IGZvciBkZWJ1Zy90ZXN0DQogICMgV04gPC0gMTkuMg0KICAjIFdOIDwtIDE5LjgNCiAgaWYoKFdOIC0gcm91bmQoV04pKSA8IDApe1dOIDwtIHJvdW5kKFdOKSAtIDF9IGVsc2Uge1dOIDwtIHJvdW5kKFdOKX0NCiAgIyBmaW5kIG51bWJlciBvZiByb3dzIHRvIGV4dHJhY3QgZGF0YQ0KICBuIDwtIG5fY29scyAqIFdODQogICMgZXh0cmFjdCByZWxldmFudCBtYXRyaXgNCiAgU3RlcDIgPC0gU3RlcDEgJT4lIA0KICAgIGhlYWQobikgJT4lICNvbmx5IHVzZSB3aG9sZSBudW1iZXIgdG8gYXZvaWQgZXJyb3JzDQogICAgdCgpICU+JSAgIyB0aGlzIGJyaW5ncyB1cyBhIG1hdHJpeA0KICAgIG1hdHJpeChucm93ID0gV04sIG5jb2wgPSBuX2NvbHMsIGJ5cm93ID0gVFJVRSkgIyB0cmFuc2Zvcm1pbmcgdGhhdCBpbnRvIG1hdHJpeCBzaXplIDIweDE1MA0KICAjIHJldHVybiB0aGUgcmVzdWx0IG9mIHRoZSBmdW5jdGlvbg0KICByZXR1cm4oU3RlcDIpDQp9DQoNCmBgYA0KDQoNCiMjIEluc3RhbGwgZnJlc2ggY29weSBvZiBoMm8NCg0KU2VlIHd3dy5oMm8uYWkgLS0+IERvd25sb2FkIC0tPiBJbnN0YWxsIGZyb20gUg0KDQpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KIyBUaGUgZm9sbG93aW5nIHR3byBjb21tYW5kcyByZW1vdmUgYW55IHByZXZpb3VzbHkgaW5zdGFsbGVkIEgyTyBwYWNrYWdlcyBmb3IgUi4NCmlmICgicGFja2FnZTpoMm8iICVpbiUgc2VhcmNoKCkpIHsgZGV0YWNoKCJwYWNrYWdlOmgybyIsIHVubG9hZD1UUlVFKSB9DQppZiAoImgybyIgJWluJSByb3duYW1lcyhpbnN0YWxsZWQucGFja2FnZXMoKSkpIHsgcmVtb3ZlLnBhY2thZ2VzKCJoMm8iKSB9DQoNCiMgTmV4dCwgd2UgZG93bmxvYWQgcGFja2FnZXMgdGhhdCBIMk8gZGVwZW5kcyBvbi4NCnBrZ3MgPC0gYygiUkN1cmwiLCJqc29ubGl0ZSIpDQpmb3IgKHBrZyBpbiBwa2dzKSB7DQppZiAoISAocGtnICVpbiUgcm93bmFtZXMoaW5zdGFsbGVkLnBhY2thZ2VzKCkpKSkgeyBpbnN0YWxsLnBhY2thZ2VzKHBrZykgfQ0KfQ0KDQojIE5vdyB3ZSBkb3dubG9hZCwgaW5zdGFsbCBhbmQgaW5pdGlhbGl6ZSB0aGUgSDJPIHBhY2thZ2UgZm9yIFIuDQppbnN0YWxsLnBhY2thZ2VzKCJoMm8iLCB0eXBlPSJzb3VyY2UiLCByZXBvcz0iaHR0cDovL2gyby1yZWxlYXNlLnMzLmFtYXpvbmF3cy5jb20vaDJvL3JlbC13aGVlbGVyLzIvUiIpDQpgYGANCg0K